Merge "Add InputRouteManager and InputMediaDevice to support input routing" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index bd17d6d..8a2616e 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -25,6 +25,7 @@
         "android.app.appfunctions.flags-aconfig-java",
         "android.app.contextualsearch.flags-aconfig-java",
         "android.app.flags-aconfig-java",
+        "android.app.jank.flags-aconfig-java",
         "android.app.ondeviceintelligence-aconfig-java",
         "android.app.smartspace.flags-aconfig-java",
         "android.app.supervision.flags-aconfig-java",
@@ -1606,3 +1607,17 @@
     aconfig_declarations: "interaction_jank_monitor_flags",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// App Jank
+aconfig_declarations {
+    name: "android.app.jank.flags-aconfig",
+    package: "android.app.jank",
+    container: "system",
+    srcs: ["core/java/android/app/jank/flags.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.app.jank.flags-aconfig-java",
+    aconfig_declarations: "android.app.jank.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java b/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
index 237c747..80cd86c 100644
--- a/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/AdditionPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,11 +34,11 @@
 public class AdditionPerfTest {
 
     @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeAddConstantToLocalInt() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         int result = 0;
         while (state.keepRunning()) {
             result += 123;
@@ -46,7 +46,7 @@
     }
     @Test
     public void timeAddTwoLocalInts() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         int result = 0;
         int constant = 123;
         while (state.keepRunning()) {
@@ -55,7 +55,7 @@
     }
     @Test
     public void timeAddConstantToLocalLong() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         long result = 0;
         while (state.keepRunning()) {
             result += 123L;
@@ -63,7 +63,7 @@
     }
     @Test
     public void timeAddTwoLocalLongs() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         long result = 0;
         long constant = 123L;
         while (state.keepRunning()) {
@@ -72,7 +72,7 @@
     }
     @Test
     public void timeAddConstantToLocalFloat() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         float result = 0.0f;
         while (state.keepRunning()) {
             result += 123.0f;
@@ -80,7 +80,7 @@
     }
     @Test
     public void timeAddTwoLocalFloats() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         float result = 0.0f;
         float constant = 123.0f;
         while (state.keepRunning()) {
@@ -89,7 +89,7 @@
     }
     @Test
     public void timeAddConstantToLocalDouble() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         double result = 0.0;
         while (state.keepRunning()) {
             result += 123.0;
@@ -97,7 +97,7 @@
     }
     @Test
     public void timeAddTwoLocalDoubles() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         double result = 0.0;
         double constant = 123.0;
         while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
index 1222bc2..2f6c378 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayCopyPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,11 +33,11 @@
 public class ArrayCopyPerfTest {
 
     @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeManualArrayCopy() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         char[] src = new char[8192];
         while (state.keepRunning()) {
             char[] dst = new char[8192];
@@ -49,7 +49,7 @@
 
     @Test
     public void time_System_arrayCopy() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         char[] src = new char[8192];
         while (state.keepRunning()) {
             char[] dst = new char[8192];
@@ -59,7 +59,7 @@
 
     @Test
     public void time_Arrays_copyOf() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         char[] src = new char[8192];
         while (state.keepRunning()) {
             char[] dst = Arrays.copyOf(src, 8192);
@@ -68,7 +68,7 @@
 
     @Test
     public void time_Arrays_copyOfRange() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         char[] src = new char[8192];
         while (state.keepRunning()) {
             char[] dst = Arrays.copyOfRange(src, 0, 8192);
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
index 3f95e3e..d17add7 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayIterationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,7 +38,7 @@
     }
 
     @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     Foo[] mArray = new Foo[27];
     {
@@ -46,7 +46,7 @@
     }
     @Test
     public void timeArrayIteration() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             int sum = 0;
             for (int i = 0; i < mArray.length; i++) {
@@ -56,7 +56,7 @@
     }
     @Test
     public void timeArrayIterationCached() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             int sum = 0;
             Foo[] localArray = mArray;
@@ -69,7 +69,7 @@
     }
     @Test
     public void timeArrayIterationForEach() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             int sum = 0;
             for (Foo a: mArray) {
diff --git a/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
index 1423a13..3a57db8 100644
--- a/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ArrayListIterationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -39,7 +39,7 @@
         int mSplat;
     }
     @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     ArrayList<Foo> mList = new ArrayList<Foo>();
     {
@@ -47,7 +47,7 @@
     }
     @Test
     public void timeArrayListIterationIndexed() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             int sum = 0;
             ArrayList<Foo> list = mList;
@@ -59,7 +59,7 @@
     }
     @Test
     public void timeArrayListIterationForEach() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             int sum = 0;
             for (Foo a : mList) {
diff --git a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
index 0283105..3fb3bc8 100644
--- a/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/BigIntegerPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,8 +38,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class BigIntegerPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     // A simple sum of products computation, mostly so we can check timing in the
     // absence of any division. Computes the sum from 1 to n of ((10^prec) << 30) + 1)^2,
@@ -62,7 +61,7 @@
     // Execute the above rep times, optionally timing it.
     @Test
     public void repeatInner() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 10; i <= 10_000; i *= 10) {
                 inner(100, i);
@@ -86,7 +85,7 @@
     // Check results for equality, and print one, to compaare against reference.
     @Test
     public void repeatHarmonic1000() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 5; i <= 5_000; i *= 10) {
                 BigInteger refRes = harmonic1000(i);
@@ -107,7 +106,7 @@
     // us to time and check it for consistency as well.
     @Test
     public void repeatToString() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 5; i <= 5_000; i *= 10) {
                 BigInteger refRes = harmonic1000(i);
@@ -147,7 +146,7 @@
     // to compare to reference.
     @Test
     public void repeatEApprox() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 10; i <= 10_000; i *= 10) {
                 BigInteger refRes = eApprox(100_000, i);
@@ -166,7 +165,7 @@
     // Test / time modPow()
     @Test
     public void repeatModPow() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 5; i <= 500; i *= 10) {
                 BigInteger odd1 = BigInteger.TEN.pow(i / 2).add(BigInteger.ONE);
@@ -199,7 +198,7 @@
     // Test / time modInverse()
     @Test
     public void repeatModInverse() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 10; i <= 10_000; i *= 10) {
                 BigInteger odd1 = BigInteger.TEN.pow(i / 2).add(BigInteger.ONE);
diff --git a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
index 11ca73a..2a1b5d1 100644
--- a/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/BufferedZipFilePerfTest.java
@@ -16,9 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
-
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -40,8 +39,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public final class BufferedZipFilePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     int[] mReadSize = new int[] {4, 32, 128};
     int[] mCompressedSize = new int[] {128, 1024, 8192, 65536};
@@ -69,7 +67,7 @@
 
     @Test
     public void timeUnbufferedRead() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mCompressedSize.length; i++) {
                 for (int j = 0; j < mReadSize.length; j++) {
@@ -89,7 +87,7 @@
 
     @Test
     public void timeBufferedRead() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mCompressedSize.length; i++) {
                 for (int j = 0; j < mReadSize.length; j++) {
diff --git a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
index 0abe194..5f599ea 100644
--- a/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ClassLoaderResourcePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,8 +30,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ClassLoaderResourcePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final String EXISTENT_RESOURCE = "java/util/logging/logging.properties";
     private static final String MISSING_RESOURCE = "missing_entry";
@@ -41,7 +40,7 @@
         ClassLoader currentClassLoader = getClass().getClassLoader();
         Assert.assertNotNull(currentClassLoader.getResource(EXISTENT_RESOURCE));
 
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             currentClassLoader.getResource(EXISTENT_RESOURCE);
         }
@@ -52,7 +51,7 @@
         ClassLoader currentClassLoader = getClass().getClassLoader();
         Assert.assertNull(currentClassLoader.getResource(MISSING_RESOURCE));
 
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             currentClassLoader.getResource(MISSING_RESOURCE);
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
index 52441d1..ea24984 100644
--- a/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ClonePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,8 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ClonePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     static class CloneableObject implements Cloneable {
         public Object clone() throws CloneNotSupportedException {
@@ -1128,7 +1127,7 @@
     public void time_Object_clone() {
         try {
             CloneableObject o = new CloneableObject();
-            final BenchmarkState state = mBenchmarkRule.getState();
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
             while (state.keepRunning()) {
                 o.clone();
             }
@@ -1141,7 +1140,7 @@
     public void time_Object_manyFieldClone() {
         try {
             CloneableManyFieldObject o = new CloneableManyFieldObject();
-            final BenchmarkState state = mBenchmarkRule.getState();
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
             while (state.keepRunning()) {
                 o.clone();
             }
@@ -1154,7 +1153,7 @@
     public void time_Object_deepClone() {
         try {
             DeepCloneable o = new DeepCloneable();
-            final BenchmarkState state = mBenchmarkRule.getState();
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
             while (state.keepRunning()) {
                 o.clone();
             }
@@ -1166,7 +1165,7 @@
     @Test
     public void time_Array_clone() {
         int[] o = new int[32];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             o.clone();
         }
@@ -1178,7 +1177,7 @@
         for (int i = 0; i < o.length / 2; ++i) {
             o[i] = new Object();
         }
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             o.clone();
         }
@@ -1190,7 +1189,7 @@
         for (int i = 0; i < o.length / 2; ++i) {
             o[i] = new Object();
         }
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             o.clone();
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
index e6c5aca..82247dc 100644
--- a/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/DeepArrayOpsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -36,8 +36,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class DeepArrayOpsPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private Object[] mArray;
     private Object[] mArray2;
@@ -100,7 +99,7 @@
     @Parameters(method = "getData")
     public void deepHashCode(int arrayLength) throws Exception {
         setUp(arrayLength);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Arrays.deepHashCode(mArray);
         }
@@ -110,7 +109,7 @@
     @Parameters(method = "getData")
     public void deepEquals(int arrayLength) throws Exception {
         setUp(arrayLength);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Arrays.deepEquals(mArray, mArray2);
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
index 378137b..0bebf04 100644
--- a/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/FieldAccessPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,8 +30,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class FieldAccessPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static class Inner {
         public int mPublicInnerIntVal;
@@ -48,7 +47,7 @@
     @Test
     public void timeField() {
         int result = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = mIntVal;
         }
@@ -57,7 +56,7 @@
     @Test
     public void timeFieldFinal() {
         int result = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = mFinalIntVal;
         }
@@ -66,7 +65,7 @@
     @Test
     public void timeFieldStatic() {
         int result = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = sStaticIntVal;
         }
@@ -75,7 +74,7 @@
     @Test
     public void timeFieldStaticFinal() {
         int result = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = FINAL_INT_VAL;
         }
@@ -85,7 +84,7 @@
     public void timeFieldCached() {
         int result = 0;
         int cachedIntVal = this.mIntVal;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = cachedIntVal;
         }
@@ -95,7 +94,7 @@
     public void timeFieldPrivateInnerClassPublicField() {
         int result = 0;
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = inner.mPublicInnerIntVal;
         }
@@ -105,7 +104,7 @@
     public void timeFieldPrivateInnerClassProtectedField() {
         int result = 0;
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = inner.mProtectedInnerIntVal;
         }
@@ -115,7 +114,7 @@
     public void timeFieldPrivateInnerClassPrivateField() {
         int result = 0;
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = inner.mPrivateInnerIntVal;
         }
@@ -125,7 +124,7 @@
     public void timeFieldPrivateInnerClassPackageField() {
         int result = 0;
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = inner.mPackageInnerIntVal;
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
index 610e8e5..55c1027 100644
--- a/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/HashedCollectionsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -35,14 +35,13 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class HashedCollectionsPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeHashMapGet() {
         HashMap<String, String> map = new HashMap<String, String>();
         map.put("hello", "world");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             map.get("hello");
         }
@@ -54,7 +53,7 @@
         synchronized (map) {
             map.put("hello", "world");
         }
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             synchronized (map) {
                 map.get("hello");
@@ -66,7 +65,7 @@
     public void timeHashtableGet() {
         Hashtable<String, String> map = new Hashtable<String, String>();
         map.put("hello", "world");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             map.get("hello");
         }
@@ -76,7 +75,7 @@
     public void timeLinkedHashMapGet() {
         LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
         map.put("hello", "world");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             map.get("hello");
         }
@@ -86,7 +85,7 @@
     public void timeConcurrentHashMapGet() {
         ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
         map.put("hello", "world");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             map.get("hello");
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
index 40c07e0..da60a77 100644
--- a/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ImtConflictPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -41,8 +41,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ImtConflictPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Before
     public void setup() {
@@ -281,7 +280,7 @@
     @Test
     public void timeConflictDepth01() {
         C0 c0 = new C0();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c0);
             callF0(c0);
@@ -309,7 +308,7 @@
     @Test
     public void timeConflictDepth02() {
         C1 c1 = new C1();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c1);
             callF19(c1);
@@ -337,7 +336,7 @@
     @Test
     public void timeConflictDepth03() {
         C2 c2 = new C2();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c2);
             callF19(c2);
@@ -365,7 +364,7 @@
     @Test
     public void timeConflictDepth04() {
         C3 c3 = new C3();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c3);
             callF19(c3);
@@ -393,7 +392,7 @@
     @Test
     public void timeConflictDepth05() {
         C4 c4 = new C4();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c4);
             callF19(c4);
@@ -421,7 +420,7 @@
     @Test
     public void timeConflictDepth06() {
         C5 c5 = new C5();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c5);
             callF19(c5);
@@ -449,7 +448,7 @@
     @Test
     public void timeConflictDepth07() {
         C6 c6 = new C6();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c6);
             callF19(c6);
@@ -477,7 +476,7 @@
     @Test
     public void timeConflictDepth08() {
         C7 c7 = new C7();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c7);
             callF19(c7);
@@ -505,7 +504,7 @@
     @Test
     public void timeConflictDepth09() {
         C8 c8 = new C8();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c8);
             callF19(c8);
@@ -533,7 +532,7 @@
     @Test
     public void timeConflictDepth10() {
         C9 c9 = new C9();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c9);
             callF19(c9);
@@ -561,7 +560,7 @@
     @Test
     public void timeConflictDepth11() {
         C10 c10 = new C10();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c10);
             callF19(c10);
@@ -589,7 +588,7 @@
     @Test
     public void timeConflictDepth12() {
         C11 c11 = new C11();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c11);
             callF19(c11);
@@ -617,7 +616,7 @@
     @Test
     public void timeConflictDepth13() {
         C12 c12 = new C12();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c12);
             callF19(c12);
@@ -645,7 +644,7 @@
     @Test
     public void timeConflictDepth14() {
         C13 c13 = new C13();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c13);
             callF19(c13);
@@ -673,7 +672,7 @@
     @Test
     public void timeConflictDepth15() {
         C14 c14 = new C14();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c14);
             callF19(c14);
@@ -701,7 +700,7 @@
     @Test
     public void timeConflictDepth16() {
         C15 c15 = new C15();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c15);
             callF19(c15);
@@ -729,7 +728,7 @@
     @Test
     public void timeConflictDepth17() {
         C16 c16 = new C16();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c16);
             callF19(c16);
@@ -757,7 +756,7 @@
     @Test
     public void timeConflictDepth18() {
         C17 c17 = new C17();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c17);
             callF19(c17);
@@ -785,7 +784,7 @@
     @Test
     public void timeConflictDepth19() {
         C18 c18 = new C18();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c18);
             callF19(c18);
@@ -813,7 +812,7 @@
     @Test
     public void timeConflictDepth20() {
         C19 c19 = new C19();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             callF0(c19);
             callF19(c19);
diff --git a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
index e1d0bf2..6d9d0c9 100644
--- a/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/MethodInvocationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,8 +30,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class MethodInvocationPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     interface I {
         void emptyInterface();
@@ -66,12 +65,12 @@
     }
 
     public void timeInternalGetter() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         new C().timeInternalGetter(state);
     }
 
     public void timeInternalFieldAccess() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         new C().timeInternalFieldAccess(state);
     }
 
@@ -79,7 +78,7 @@
     @Test
     public void timeStringLength() {
         int result = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = "hello, world!".length();
         }
@@ -88,7 +87,7 @@
     @Test
     public void timeEmptyStatic() {
         C c = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             c.emptyStatic();
         }
@@ -97,7 +96,7 @@
     @Test
     public void timeEmptyVirtual() {
         C c = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             c.emptyVirtual();
         }
@@ -106,7 +105,7 @@
     @Test
     public void timeEmptyInterface() {
         I c = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             c.emptyInterface();
         }
@@ -139,7 +138,7 @@
     @Test
     public void timePrivateInnerPublicMethod() {
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             inner.publicMethod();
         }
@@ -148,7 +147,7 @@
     @Test
     public void timePrivateInnerProtectedMethod() {
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             inner.protectedMethod();
         }
@@ -157,7 +156,7 @@
     @Test
     public void timePrivateInnerPrivateMethod() {
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             inner.privateMethod();
         }
@@ -166,7 +165,7 @@
     @Test
     public void timePrivateInnerPackageMethod() {
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             inner.packageMethod();
         }
@@ -175,7 +174,7 @@
     @Test
     public void timePrivateInnerFinalPackageMethod() {
         Inner inner = new Inner();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             inner.finalPackageMethod();
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
index c5e9d1e..09b0977 100644
--- a/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/MultiplicationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,13 +30,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class MultiplicationPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeMultiplyIntByConstant10() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 10;
         }
@@ -45,7 +44,7 @@
     @Test
     public void timeMultiplyIntByConstant8() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 8;
         }
@@ -55,7 +54,7 @@
     public void timeMultiplyIntByVariable10() {
         int result = 1;
         int factor = 10;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= factor;
         }
@@ -65,7 +64,7 @@
     public void timeMultiplyIntByVariable8() {
         int result = 1;
         int factor = 8;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= factor;
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
index d073f91..ba21ed3 100644
--- a/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ReferenceGetPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -35,8 +35,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReferenceGetPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     boolean mIntrinsicDisabled;
 
@@ -52,7 +51,7 @@
     @Test
     public void timeSoftReferenceGet() throws Exception {
         Reference soft = new SoftReference(mObj);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Object o = soft.get();
         }
@@ -61,7 +60,7 @@
     @Test
     public void timeWeakReferenceGet() throws Exception {
         Reference weak = new WeakReference(mObj);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Object o = weak.get();
         }
@@ -72,7 +71,7 @@
         Reference weak = new WeakReference(mObj);
         mObj = null;
         Runtime.getRuntime().gc();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Object o = weak.get();
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
index af13773..293752e 100644
--- a/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ReferencePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,8 +34,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReferencePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private Object mObject;
 
@@ -43,7 +42,7 @@
     @Test
     public void timeAlloc() {
         ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new PhantomReference(mObject, queue);
         }
@@ -53,7 +52,7 @@
     @Test
     public void timeAllocAndEnqueue() {
         ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             (new PhantomReference<Object>(mObject, queue)).enqueue();
         }
@@ -63,7 +62,7 @@
     @Test
     public void timeAllocEnqueueAndPoll() {
         ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             (new PhantomReference<Object>(mObject, queue)).enqueue();
             queue.poll();
@@ -74,7 +73,7 @@
     @Test
     public void timeAllocEnqueueAndRemove() {
         ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             (new PhantomReference<Object>(mObject, queue)).enqueue();
             try {
@@ -103,7 +102,7 @@
         // Allocate a bunch of finalizable objects.
         int n = 0;
         AtomicInteger count = new AtomicInteger(0);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             n++;
             new FinalizableObject(count);
diff --git a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
index cf573fa..528b751 100644
--- a/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/SmallBigIntegerPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -41,9 +41,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class SmallBigIntegerPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
-
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     // We allocate about 2 1/3 BigIntegers per iteration.
     // Assuming 100 bytes/BigInteger, this gives us around 500MB total.
     static final BigInteger BIG_THREE = BigInteger.valueOf(3);
@@ -53,7 +51,7 @@
     public void testSmallBigInteger() {
         final Random r = new Random();
         BigInteger x = new BigInteger(20, r);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             // We know this converges, but the compiler doesn't.
             if (x.and(BigInteger.ONE).equals(BigInteger.ONE)) {
diff --git a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
index d28154c..1f301ac 100644
--- a/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/StringDexCachePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,14 +30,13 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringDexCachePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeStringDexCacheAccess() {
         int v = 0;
         int count = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             // Deliberately obscured to make optimizations less likely.
             String s = (count >= 0) ? "hello, world!" : null;
diff --git a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
index 40a8db0..4268325 100644
--- a/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/StringIterationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,13 +30,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringIterationPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeStringIteration0() {
         String s = "hello, world!";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             char ch;
             for (int i = 0; i < s.length(); ++i) {
@@ -48,7 +47,7 @@
     @Test
     public void timeStringIteration1() {
         String s = "hello, world!";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             char ch;
             for (int i = 0, length = s.length(); i < length; ++i) {
@@ -60,7 +59,7 @@
     @Test
     public void timeStringIteration2() {
         String s = "hello, world!";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             char ch;
             char[] chars = s.toCharArray();
@@ -73,7 +72,7 @@
     @Test
     public void timeStringToCharArray() {
         String s = "hello, world!";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             char[] chars = s.toCharArray();
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
index 147ea50..cb3d3ac 100644
--- a/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/VirtualVersusInterfacePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -36,13 +36,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VirtualVersusInterfacePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeMapPut() {
         Map<String, String> map = new HashMap<String, String>();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             map.put("hello", "world");
         }
@@ -51,7 +50,7 @@
     @Test
     public void timeHashMapPut() {
         HashMap<String, String> map = new HashMap<String, String>();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             map.put("hello", "world");
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
index bb1c298..5be8ee6 100644
--- a/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -36,8 +36,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class XmlSerializePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private Object[] getParams() {
         return new Object[][] {
@@ -109,7 +108,7 @@
 
     private void internalTimeSerializer(Constructor<? extends XmlSerializer> ctor, int seed)
             throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             serializeRandomXml(ctor, seed);
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
index 9360a25..a37b89d 100644
--- a/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/XmlSerializerPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 import android.util.Xml;
 
 import androidx.test.filters.LargeTest;
@@ -44,11 +44,11 @@
 public class XmlSerializerPerfTest {
 
     @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeFastSerializer_nonIndent_depth100() throws IOException {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             XmlSerializer serializer = Xml.newFastSerializer();
             runTest(serializer, 100);
@@ -57,7 +57,7 @@
 
     @Test
     public void timeFastSerializer_indent_depth100() throws IOException {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             XmlSerializer serializer = Xml.newFastSerializer();
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
@@ -67,7 +67,7 @@
 
     @Test
     public void timeKXmlSerializer_nonIndent_depth100() throws IOException {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             XmlSerializer serializer = XmlObjectFactory.newXmlSerializer();
             runTest(serializer, 100);
@@ -76,7 +76,7 @@
 
     @Test
     public void timeKXmlSerializer_indent_depth100() throws IOException {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             XmlSerializer serializer = XmlObjectFactory.newXmlSerializer();
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index 03f183a..ed669be 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -42,8 +42,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class ZipFilePerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private File mFile;
 
@@ -66,7 +65,7 @@
     @Parameters(method = "getData")
     public void timeZipFileOpen(int numEntries) throws Exception {
         setUp(numEntries);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ZipFile zf = new ZipFile(mFile);
             state.pauseTiming();
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
index 3614061..d239a05 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFileReadPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -44,8 +44,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class ZipFileReadPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(new Object[][] {{1024}, {16384}, {65536}});
@@ -92,7 +91,7 @@
     @Parameters(method = "getData")
     public void timeZipFileRead(int readBufferSize) throws Exception {
         byte[] readBuffer = new byte[readBufferSize];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ZipFile zipFile = new ZipFile(mFile);
             for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
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 8890f51..487295c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/AnnotatedElementPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -35,8 +35,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class AnnotatedElementPerfTest {
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private Class<?> mType;
     private Field mField;
@@ -53,7 +52,7 @@
 
     @Test
     public void timeGetTypeAnnotations() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mType.getAnnotations();
         }
@@ -61,7 +60,7 @@
 
     @Test
     public void timeGetFieldAnnotations() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.getAnnotations();
         }
@@ -69,7 +68,7 @@
 
     @Test
     public void timeGetMethodAnnotations() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mMethod.getAnnotations();
         }
@@ -77,7 +76,7 @@
 
     @Test
     public void timeGetParameterAnnotations() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mMethod.getParameterAnnotations();
         }
@@ -85,7 +84,7 @@
 
     @Test
     public void timeGetTypeAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mType.getAnnotation(Marker.class);
         }
@@ -93,7 +92,7 @@
 
     @Test
     public void timeGetFieldAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.getAnnotation(Marker.class);
         }
@@ -101,7 +100,7 @@
 
     @Test
     public void timeGetMethodAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mMethod.getAnnotation(Marker.class);
         }
@@ -109,7 +108,7 @@
 
     @Test
     public void timeIsTypeAnnotationPresent() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mType.isAnnotationPresent(Marker.class);
         }
@@ -117,7 +116,7 @@
 
     @Test
     public void timeIsFieldAnnotationPresent() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.isAnnotationPresent(Marker.class);
         }
@@ -125,7 +124,7 @@
 
     @Test
     public void timeIsMethodAnnotationPresent() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mMethod.isAnnotationPresent(Marker.class);
         }
@@ -135,7 +134,7 @@
 
     @Test
     public void timeGetAllReturnsLargeAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasLargeAnnotation.class.getAnnotations();
         }
@@ -143,7 +142,7 @@
 
     @Test
     public void timeGetAllReturnsSmallAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasSmallAnnotation.class.getAnnotations();
         }
@@ -151,7 +150,7 @@
 
     @Test
     public void timeGetAllReturnsMarkerAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasMarkerAnnotation.class.getAnnotations();
         }
@@ -159,7 +158,7 @@
 
     @Test
     public void timeGetAllReturnsNoAnnotation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasNoAnnotations.class.getAnnotations();
         }
@@ -167,7 +166,7 @@
 
     @Test
     public void timeGetAllReturnsThreeAnnotations() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasThreeAnnotations.class.getAnnotations();
         }
@@ -177,7 +176,7 @@
 
     @Test
     public void timeGetAnnotationsOnSubclass() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ExtendsHasThreeAnnotations.class.getAnnotations();
         }
@@ -185,7 +184,7 @@
 
     @Test
     public void timeGetDeclaredAnnotationsOnSubclass() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ExtendsHasThreeAnnotations.class.getDeclaredAnnotations();
         }
@@ -195,7 +194,7 @@
 
     @Test
     public void timeGetDeclaredClasses() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             AnnotatedElementPerfTest.class.getDeclaredClasses();
         }
@@ -203,7 +202,7 @@
 
     @Test
     public void timeGetDeclaringClass() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasSmallAnnotation.class.getDeclaringClass();
         }
@@ -212,7 +211,7 @@
     @Test
     public void timeGetEnclosingClass() {
         Object anonymousClass = new Object() {};
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             anonymousClass.getClass().getEnclosingClass();
         }
@@ -221,7 +220,7 @@
     @Test
     public void timeGetEnclosingConstructor() {
         Object anonymousClass = new Object() {};
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             anonymousClass.getClass().getEnclosingConstructor();
         }
@@ -230,7 +229,7 @@
     @Test
     public void timeGetEnclosingMethod() {
         Object anonymousClass = new Object() {};
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             anonymousClass.getClass().getEnclosingMethod();
         }
@@ -238,7 +237,7 @@
 
     @Test
     public void timeGetModifiers() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasSmallAnnotation.class.getModifiers();
         }
@@ -246,7 +245,7 @@
 
     @Test
     public void timeGetSimpleName() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasSmallAnnotation.class.getSimpleName();
         }
@@ -255,7 +254,7 @@
     @Test
     public void timeIsAnonymousClass() {
         Object anonymousClass = new Object() {};
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             anonymousClass.getClass().isAnonymousClass();
         }
@@ -263,7 +262,7 @@
 
     @Test
     public void timeIsLocalClass() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             HasSmallAnnotation.class.isLocalClass();
         }
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 baab860..adc5d8c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BidiPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,14 +34,14 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class BidiPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final AttributedCharacterIterator CHAR_ITER =
             DecimalFormat.getInstance().formatToCharacterIterator(new BigDecimal(Math.PI));
 
     @Test
     public void time_createBidiFromIter() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi bidi = new Bidi(CHAR_ITER);
         }
@@ -49,7 +49,7 @@
 
     @Test
     public void time_createBidiFromCharArray() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi bd =
                     new Bidi(
@@ -64,7 +64,7 @@
 
     @Test
     public void time_createBidiFromString() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi bidi = new Bidi("Hello", Bidi.DIRECTION_LEFT_TO_RIGHT);
         }
@@ -72,7 +72,7 @@
 
     @Test
     public void time_reorderVisually() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi.reorderVisually(
                     new byte[] {2, 1, 3, 0, 4}, 0, new String[] {"H", "e", "l", "l", "o"}, 0, 5);
@@ -81,7 +81,7 @@
 
     @Test
     public void time_hebrewBidi() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi bd =
                     new Bidi(
@@ -104,7 +104,7 @@
 
     @Test
     public void time_complicatedOverrideBidi() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi bd =
                     new Bidi(
@@ -119,7 +119,7 @@
 
     @Test
     public void time_requiresBidi() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Bidi.requiresBidi("\u05D0".toCharArray(), 1, 1); // false.
             Bidi.requiresBidi("\u05D0".toCharArray(), 0, 1); // true.
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 8a539f8..286d703 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BigIntegerPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,14 +32,14 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class BigIntegerPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeRandomDivision() throws Exception {
         Random r = new Random();
         BigInteger x = new BigInteger(1024, r);
         BigInteger y = new BigInteger(1024, r);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x.divide(y);
         }
@@ -50,7 +50,7 @@
         Random r = new Random();
         BigInteger x = new BigInteger(1024, r);
         BigInteger y = new BigInteger(1024, r);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x.gcd(y);
         }
@@ -61,7 +61,7 @@
         Random r = new Random();
         BigInteger x = new BigInteger(1024, r);
         BigInteger y = new BigInteger(1024, r);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x.multiply(y);
         }
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 1b46ff4..d646202 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BitSetPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -35,7 +35,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class BitSetPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(new Object[][] {{1000}, {10000}});
@@ -45,7 +45,7 @@
     @Parameters(method = "getData")
     public void timeIsEmptyTrue(int size) {
         BitSet bitSet = new BitSet(size);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             if (!bitSet.isEmpty()) throw new RuntimeException();
         }
@@ -56,7 +56,7 @@
     public void timeIsEmptyFalse(int size) {
         BitSet bitSet = new BitSet(size);
         bitSet.set(bitSet.size() - 1);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             if (bitSet.isEmpty()) throw new RuntimeException();
         }
@@ -66,7 +66,7 @@
     @Parameters(method = "getData")
     public void timeGet(int size) {
         BitSet bitSet = new BitSet(size);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         int i = 1;
         while (state.keepRunning()) {
             bitSet.get(++i % size);
@@ -77,7 +77,7 @@
     @Parameters(method = "getData")
     public void timeClear(int size) {
         BitSet bitSet = new BitSet(size);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         int i = 1;
         while (state.keepRunning()) {
             bitSet.clear(++i % size);
@@ -89,7 +89,7 @@
     public void timeSet(int size) {
         BitSet bitSet = new BitSet(size);
         int i = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             bitSet.set(++i % size);
         }
@@ -100,7 +100,7 @@
     public void timeSetOn(int size) {
         BitSet bitSet = new BitSet(size);
         int i = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             bitSet.set(++i % size, true);
         }
@@ -111,7 +111,7 @@
     public void timeSetOff(int size) {
         BitSet bitSet = new BitSet(size);
         int i = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             bitSet.set(++i % size, false);
         }
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 3c5e4fd..b887f40 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BreakIteratorPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -36,7 +36,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public final class BreakIteratorPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public enum Text {
         LIPSUM(
@@ -165,7 +165,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeBreakIterator(Text text) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             BreakIterator it = BreakIterator.getLineInstance(text.mLocale);
             it.setText(text.mText);
@@ -179,7 +179,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeIcuBreakIterator(Text text) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             android.icu.text.BreakIterator it =
                     android.icu.text.BreakIterator.getLineInstance(text.mLocale);
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 6df67bc..e4eaf12 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/BulkPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -39,7 +39,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class BulkPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -120,7 +120,7 @@
             throws Exception {
         ByteBuffer src = BulkPerfTest.newBuffer(align, sBuf, size);
         ByteBuffer data = BulkPerfTest.newBuffer(align, dBuf, size);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(align ? 0 : 1);
             data.position(align ? 0 : 1);
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 f01ac02..42e3910a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -46,7 +46,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class ByteBufferPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public enum MyByteOrder {
         BIG(ByteOrder.BIG_ENDIAN),
@@ -121,7 +121,7 @@
     public void timeByteBuffer_getByte(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -136,7 +136,7 @@
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
         byte[] dst = new byte[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(aligned ? 0 : 1);
@@ -150,7 +150,7 @@
     public void timeByteBuffer_getByte_indexed(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -164,7 +164,7 @@
     public void timeByteBuffer_getChar(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -180,7 +180,7 @@
         CharBuffer src =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asCharBuffer();
         char[] dst = new char[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(0);
@@ -194,7 +194,7 @@
     public void timeByteBuffer_getChar_indexed(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -208,7 +208,7 @@
     public void timeByteBuffer_getDouble(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -224,7 +224,7 @@
         DoubleBuffer src =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asDoubleBuffer();
         double[] dst = new double[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(0);
@@ -238,7 +238,7 @@
     public void timeByteBuffer_getFloat(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -254,7 +254,7 @@
         FloatBuffer src =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asFloatBuffer();
         float[] dst = new float[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(0);
@@ -268,7 +268,7 @@
     public void timeByteBuffer_getInt(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -283,7 +283,7 @@
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         IntBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asIntBuffer();
         int[] dst = new int[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(0);
@@ -297,7 +297,7 @@
     public void timeByteBuffer_getLong(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -313,7 +313,7 @@
         LongBuffer src =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asLongBuffer();
         long[] dst = new long[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(0);
@@ -327,7 +327,7 @@
     public void timeByteBuffer_getShort(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -343,7 +343,7 @@
         ShortBuffer src =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asShortBuffer();
         short[] dst = new short[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 src.position(0);
@@ -361,7 +361,7 @@
     public void timeByteBuffer_putByte(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(0);
             for (int i = 0; i < 1024; ++i) {
@@ -376,7 +376,7 @@
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
         byte[] src = new byte[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(aligned ? 0 : 1);
@@ -390,7 +390,7 @@
     public void timeByteBuffer_putChar(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -406,7 +406,7 @@
         CharBuffer dst =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asCharBuffer();
         char[] src = new char[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(0);
@@ -420,7 +420,7 @@
     public void timeByteBuffer_putDouble(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -436,7 +436,7 @@
         DoubleBuffer dst =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asDoubleBuffer();
         double[] src = new double[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(0);
@@ -450,7 +450,7 @@
     public void timeByteBuffer_putFloat(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -466,7 +466,7 @@
         FloatBuffer dst =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asFloatBuffer();
         float[] src = new float[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(0);
@@ -480,7 +480,7 @@
     public void timeByteBuffer_putInt(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -495,7 +495,7 @@
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         IntBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asIntBuffer();
         int[] src = new int[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(0);
@@ -509,7 +509,7 @@
     public void timeByteBuffer_putLong(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -525,7 +525,7 @@
         LongBuffer dst =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asLongBuffer();
         long[] src = new long[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(0);
@@ -539,7 +539,7 @@
     public void timeByteBuffer_putShort(
             MyByteOrder byteOrder, boolean aligned, MyBufferType bufferType) throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             for (int i = 0; i < 1024; ++i) {
@@ -555,7 +555,7 @@
         ShortBuffer dst =
                 ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType).asShortBuffer();
         short[] src = new short[1024];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < 1024; ++i) {
                 dst.position(0);
@@ -566,7 +566,7 @@
 
     @Test
     public void time_new_byteArray() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             byte[] bs = new byte[8192];
         }
@@ -574,7 +574,7 @@
 
     @Test
     public void time_ByteBuffer_allocate() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ByteBuffer bs = ByteBuffer.allocate(8192);
         }
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 8c318cd..9ee927c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferScalarVersusVectorPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -35,7 +35,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class ByteBufferScalarVersusVectorPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -112,7 +112,7 @@
             throws Exception {
         ByteBuffer src = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
         ByteBuffer dst = ByteBufferPerfTest.newBuffer(byteOrder, aligned, bufferType);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(0);
             dst.position(0);
@@ -127,7 +127,7 @@
     public void timeByteBufferBulkGet(boolean aligned) throws Exception {
         ByteBuffer src = ByteBuffer.allocate(aligned ? 8192 : 8192 + 1);
         byte[] dst = new byte[8192];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             src.get(dst, 0, dst.length);
@@ -139,7 +139,7 @@
     public void timeDirectByteBufferBulkGet(boolean aligned) throws Exception {
         ByteBuffer src = ByteBuffer.allocateDirect(aligned ? 8192 : 8192 + 1);
         byte[] dst = new byte[8192];
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             src.position(aligned ? 0 : 1);
             src.get(dst, 0, dst.length);
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 12c1f8c..e4a4db7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharacterPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -38,7 +38,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class CharacterPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -84,7 +84,7 @@
     public void timeIsSpace(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
         boolean fake = false;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -104,7 +104,7 @@
     @Parameters(method = "getData")
     public void timeDigit(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -124,7 +124,7 @@
     @Parameters(method = "getData")
     public void timeGetNumericValue(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -144,7 +144,7 @@
     @Parameters(method = "getData")
     public void timeIsDigit(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -164,7 +164,7 @@
     @Parameters(method = "getData")
     public void timeIsIdentifierIgnorable(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -184,7 +184,7 @@
     @Parameters(method = "getData")
     public void timeIsJavaIdentifierPart(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -204,7 +204,7 @@
     @Parameters(method = "getData")
     public void timeIsJavaIdentifierStart(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -224,7 +224,7 @@
     @Parameters(method = "getData")
     public void timeIsLetter(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -244,7 +244,7 @@
     @Parameters(method = "getData")
     public void timeIsLetterOrDigit(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -264,7 +264,7 @@
     @Parameters(method = "getData")
     public void timeIsLowerCase(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -284,7 +284,7 @@
     @Parameters(method = "getData")
     public void timeIsSpaceChar(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -304,7 +304,7 @@
     @Parameters(method = "getData")
     public void timeIsUpperCase(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -324,7 +324,7 @@
     @Parameters(method = "getData")
     public void timeIsWhitespace(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -344,7 +344,7 @@
     @Parameters(method = "getData")
     public void timeToLowerCase(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
@@ -364,7 +364,7 @@
     @Parameters(method = "getData")
     public void timeToUpperCase(CharacterSet characterSet, Overload overload) {
         setUp(characterSet);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         if (overload == Overload.CHAR) {
             while (state.keepRunning()) {
                 for (int ch = 0; ch < 65536; ++ch) {
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 4dd890a..858c101 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetForNamePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -33,7 +33,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class CharsetForNamePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static String[] charsetNames() {
         return new String[] {
@@ -52,7 +52,7 @@
     @Test
     @Parameters(method = "charsetNames")
     public void timeCharsetForName(String charsetName) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Charset.forName(charsetName);
         }
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 3a71ce9..a2fb7d7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -34,7 +34,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class CharsetPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -91,7 +91,7 @@
     @Parameters(method = "getData")
     public void time_new_String_BString(int length, String name) throws Exception {
         byte[] bytes = makeBytes(makeString(length));
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new String(bytes, name);
         }
@@ -101,7 +101,7 @@
     @Parameters(method = "getData")
     public void time_new_String_BII(int length, String name) throws Exception {
         byte[] bytes = makeBytes(makeString(length));
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new String(bytes, 0, bytes.length);
         }
@@ -111,7 +111,7 @@
     @Parameters(method = "getData")
     public void time_new_String_BIIString(int length, String name) throws Exception {
         byte[] bytes = makeBytes(makeString(length));
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new String(bytes, 0, bytes.length, name);
         }
@@ -121,7 +121,7 @@
     @Parameters(method = "getData")
     public void time_String_getBytes(int length, String name) throws Exception {
         String string = makeString(length);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             string.getBytes(name);
         }
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 6c30a16..2047444 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java
@@ -16,8 +16,8 @@
 package android.libcore.regression;
 
 import android.icu.lang.UCharacter;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -35,7 +35,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class CharsetUtf8PerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private void makeUnicodeRange(int startingCodePoint, int endingCodePoint) {
         StringBuilder builder = new StringBuilder();
@@ -46,7 +46,7 @@
         }
 
         String str = builder.toString();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder builder2 = new StringBuilder();
             builder2.append(str);
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 dcdfd37..4ce8b41 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ChecksumPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,13 +32,13 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ChecksumPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeAdler_block() throws Exception {
         byte[] bytes = new byte[10000];
         Adler32 adler = new Adler32();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             adler.update(bytes);
         }
@@ -47,7 +47,7 @@
     @Test
     public void timeAdler_byte() throws Exception {
         Adler32 adler = new Adler32();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             adler.update(1);
         }
@@ -57,7 +57,7 @@
     public void timeCrc_block() throws Exception {
         byte[] bytes = new byte[10000];
         CRC32 crc = new CRC32();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             crc.update(bytes);
         }
@@ -66,7 +66,7 @@
     @Test
     public void timeCrc_byte() throws Exception {
         CRC32 crc = new CRC32();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             crc.update(1);
         }
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 6c175b1..6a7ec1a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherInputStreamPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -41,7 +41,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class CipherInputStreamPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final int DATA_SIZE = 1024 * 1024;
     private static final byte[] DATA = new byte[DATA_SIZE];
@@ -80,7 +80,7 @@
 
     @Test
     public void timeEncrypt() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mCipherEncrypt.init(Cipher.ENCRYPT_MODE, mKey, mSpec);
             InputStream is = new CipherInputStream(new ByteArrayInputStream(DATA), mCipherEncrypt);
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 136822e..238c028 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CipherPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -47,7 +47,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class CipherPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection getCases() {
         int[] keySizes = new int[] {128, 192, 256};
@@ -180,7 +180,7 @@
             Mode mode, Padding padding, int keySize, int inputSize, Implementation implementation)
             throws Exception {
         setUp(mode, padding, keySize, implementation);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mCipherEncrypt.doFinal(DATA, 0, inputSize, mOutput);
         }
@@ -192,7 +192,7 @@
             Mode mode, Padding padding, int keySize, int inputSize, Implementation implementation)
             throws Exception {
         setUp(mode, padding, keySize, implementation);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mCipherDecrypt.doFinal(DATA, 0, inputSize, mOutput);
         }
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 9efb7ce..7e55660 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollatorPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class CollatorPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final RuleBasedCollator COLLATOR =
             (RuleBasedCollator) Collator.getInstance(Locale.US);
@@ -41,7 +41,7 @@
     @Test
     public void timeCollatorPrimary() {
         COLLATOR.setStrength(Collator.PRIMARY);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             COLLATOR.compare("abcde", "abcdf");
             COLLATOR.compare("abcde", "abcde");
@@ -52,7 +52,7 @@
     @Test
     public void timeCollatorSecondary() {
         COLLATOR.setStrength(Collator.SECONDARY);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             COLLATOR.compare("abcdÂ", "abcdÄ");
             COLLATOR.compare("abcdÂ", "abcdÂ");
@@ -63,7 +63,7 @@
     @Test
     public void timeCollatorTertiary() {
         COLLATOR.setStrength(Collator.TERTIARY);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             COLLATOR.compare("abcdE", "abcde");
             COLLATOR.compare("abcde", "abcde");
@@ -74,7 +74,7 @@
     @Test
     public void timeCollatorIdentical() {
         COLLATOR.setStrength(Collator.IDENTICAL);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             COLLATOR.compare("abcdȪ", "abcdȫ");
             COLLATOR.compare("abcdȪ", "abcdȪ");
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 4e5ceaf..100798a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/CollectionsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -40,7 +40,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class CollectionsPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(new Object[][] {{4}, {16}, {64}, {256}, {1024}});
@@ -60,7 +60,7 @@
     @Parameters(method = "getData")
     public void timeSort_arrayList(int arrayListLength) throws Exception {
         List<Integer> input = buildList(arrayListLength, ArrayList.class);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Collections.sort(input);
         }
@@ -70,7 +70,7 @@
     @Parameters(method = "getData")
     public void timeSortWithComparator_arrayList(int arrayListLength) throws Exception {
         List<Integer> input = buildList(arrayListLength, ArrayList.class);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Collections.sort(input, REVERSE);
         }
@@ -80,7 +80,7 @@
     @Parameters(method = "getData")
     public void timeSort_vector(int arrayListLength) throws Exception {
         List<Integer> input = buildList(arrayListLength, Vector.class);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Collections.sort(input);
         }
@@ -90,7 +90,7 @@
     @Parameters(method = "getData")
     public void timeSortWithComparator_vector(int arrayListLength) throws Exception {
         List<Integer> input = buildList(arrayListLength, Vector.class);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Collections.sort(input, REVERSE);
         }
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 b0ccd99..b6784a8 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DateFormatPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public final class DateFormatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private Locale mLocale1;
     private Locale mLocale2;
@@ -50,7 +50,7 @@
 
     @Test
     public void timeGetDateTimeInstance() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DateFormat.getDateTimeInstance();
         }
@@ -58,7 +58,7 @@
 
     @Test
     public void timeGetDateTimeInstance_multiple() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale1);
             DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, mLocale2);
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 3a2f6fa..52f9873 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,7 +34,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class DecimalFormatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final String EXP_PATTERN = "##E0";
 
@@ -58,7 +58,7 @@
     public void formatWithGrouping(Object obj) {
         DF.setGroupingSize(3);
         DF.setGroupingUsed(true);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DF.format(obj);
         }
@@ -66,21 +66,21 @@
 
     public void format(String pattern, Object obj) {
         PATTERN_INSTANCE.applyPattern(pattern);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             PATTERN_INSTANCE.format(obj);
         }
     }
 
     public void format(Object obj) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DF.format(obj);
         }
     }
 
     public void formatToCharacterIterator(Object obj) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DF.formatToCharacterIterator(obj);
         }
@@ -88,14 +88,14 @@
 
 
     public void formatCurrencyUS(Object obj) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DF_CURRENCY_US.format(obj);
         }
     }
 
     public void formatCurrencyFR(Object obj) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DF_CURRENCY_FR.format(obj);
         }
@@ -213,7 +213,7 @@
 
     @Test
     public void time_instantiation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new DecimalFormat();
         }
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 4bc550e..6105420 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DecimalFormatSymbolsPerfTest.java
@@ -15,8 +15,8 @@
  */
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,13 +31,13 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class DecimalFormatSymbolsPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static Locale sLocale = Locale.getDefault(Locale.Category.FORMAT);
 
     @Test
     public void time_instantiation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new DecimalFormatSymbols(sLocale);
         }
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 597447b..fae74a5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DefaultCharsetPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class DefaultCharsetPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void time_defaultCharset() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Charset.defaultCharset();
         }
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 b17d0f4..2915363 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DnsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class DnsPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeDns() throws Exception {
@@ -53,7 +53,7 @@
                 "www.cnn.com",
                 "bad.host.mtv.corp.google.com",
         };
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         int i = 0;
         while (state.keepRunning()) {
             try {
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 4c8a8ea..dd7e5cc 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoPrivilegedPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,11 +32,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class DoPrivilegedPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeDirect() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String lineSeparator = System.getProperty("line.separator");
         }
@@ -44,7 +44,7 @@
 
     @Test
     public void timeFastAndSlow() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String lineSeparator;
             if (System.getSecurityManager() == null) {
@@ -61,7 +61,7 @@
 
     @Test
     public void timeNewAction() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String lineSeparator = AccessController.doPrivileged(new PrivilegedAction<String>() {
                 public String run() {
@@ -74,7 +74,7 @@
     @Test
     public void timeReusedAction() throws Exception {
         final PrivilegedAction<String> action = new ReusableAction("line.separator");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String lineSeparator = AccessController.doPrivileged(action);
         }
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 4ff65b1..e034a47 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/DoublePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class DoublePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private double mD = 1.2;
     private long mL = 4608083138725491507L;
@@ -37,7 +37,7 @@
     @Test
     public void timeDoubleToLongBits() {
         long result = 123;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Double.doubleToLongBits(mD);
         }
@@ -49,7 +49,7 @@
     @Test
     public void timeDoubleToRawLongBits() {
         long result = 123;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Double.doubleToRawLongBits(mD);
         }
@@ -61,7 +61,7 @@
     @Test
     public void timeLongBitsToDouble() {
         double result = 123.0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Double.longBitsToDouble(mL);
         }
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 aacdcee1..fe1b599 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/EqualsHashCodePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -37,7 +37,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public final class EqualsHashCodePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private enum Type {
         URI() {
@@ -82,7 +82,7 @@
         mA2 = type.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox");
         mB1 = type.newInstance("http://developer.android.com/reference/java/net/URI.html");
         mB2 = type.newInstance("http://developer.android.com/reference/java/net/URI.html");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mA1.equals(mB1);
             mA1.equals(mA2);
@@ -95,7 +95,7 @@
     public void timeHashCode(Type type) throws Exception {
         mA1 = type.newInstance("https://mail.google.com/mail/u/0/?shva=1#inbox");
         mB1 = type.newInstance("http://developer.android.com/reference/java/net/URI.html");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mA1.hashCode();
             mB1.hashCode();
@@ -112,7 +112,7 @@
                         "http://developer.android.com/query?q="
                                 + QUERY.substring(0, QUERY.length() - 3)
                                 + "%AF");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mC1.equals(mC2);
         }
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 9a6864e..ecbfc71 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -41,11 +41,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ExpensiveObjectsPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeNewDateFormatTimeInstance() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
             df.format(System.currentTimeMillis());
@@ -55,7 +55,7 @@
     @Test(timeout = 900000)
     public void timeClonedDateFormatTimeInstance() {
         DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ((DateFormat) df.clone()).format(System.currentTimeMillis());
         }
@@ -64,7 +64,7 @@
     @Test
     public void timeReusedDateFormatTimeInstance() {
         DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             synchronized (df) {
                 df.format(System.currentTimeMillis());
@@ -74,7 +74,7 @@
 
     @Test(timeout = 900000)
     public void timeNewCollator() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Collator.getInstance(Locale.US);
         }
@@ -83,7 +83,7 @@
     @Test
     public void timeClonedCollator() {
         Collator c = Collator.getInstance(Locale.US);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             c.clone();
         }
@@ -91,7 +91,7 @@
 
     @Test
     public void timeNewDateFormatSymbols() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new DateFormatSymbols(Locale.US);
         }
@@ -100,7 +100,7 @@
     @Test
     public void timeClonedDateFormatSymbols() {
         DateFormatSymbols dfs = new DateFormatSymbols(Locale.US);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             dfs.clone();
         }
@@ -108,7 +108,7 @@
 
     @Test
     public void timeNewDecimalFormatSymbols() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new DecimalFormatSymbols(Locale.US);
         }
@@ -117,7 +117,7 @@
     @Test
     public void timeClonedDecimalFormatSymbols() {
         DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             dfs.clone();
         }
@@ -125,7 +125,7 @@
 
     @Test
     public void timeNewNumberFormat() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             NumberFormat.getInstance(Locale.US);
         }
@@ -134,7 +134,7 @@
     @Test
     public void timeClonedNumberFormat() {
         NumberFormat nf = NumberFormat.getInstance(Locale.US);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             nf.clone();
         }
@@ -142,7 +142,7 @@
 
     @Test
     public void timeLongToString() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Long.toString(1024L);
         }
@@ -151,7 +151,7 @@
     @Test
     public void timeNumberFormatTrivialFormatDouble() {
         NumberFormat nf = NumberFormat.getInstance(Locale.US);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             nf.format(1024.0);
         }
@@ -159,7 +159,7 @@
 
     @Test
     public void timeNewSimpleDateFormat() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new SimpleDateFormat();
         }
@@ -167,7 +167,7 @@
 
     @Test
     public void timeNewGregorianCalendar() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new GregorianCalendar();
         }
@@ -176,7 +176,7 @@
     @Test
     public void timeClonedGregorianCalendar() {
         GregorianCalendar gc = new GregorianCalendar();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             gc.clone();
         }
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 cef7e8c7..0c14d64 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FilePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public final class FilePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeFileCreationWithEmptyChild() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new File("/foo", "/");
         }
@@ -43,7 +43,7 @@
 
     @Test
     public void timeFileCreationWithNormalizationNecessary() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new File("/foo//bar//baz//bag", "/baz/");
         }
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 645c023..7d7d83b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FloatPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class FloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private float mFloat = 1.2f;
     private int mInt = 1067030938;
@@ -37,7 +37,7 @@
     @Test
     public void timeFloatToIntBits() {
         int result = 123;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Float.floatToIntBits(mFloat);
         }
@@ -49,7 +49,7 @@
     @Test
     public void timeFloatToRawIntBits() {
         int result = 123;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Float.floatToRawIntBits(mFloat);
         }
@@ -61,7 +61,7 @@
     @Test
     public void timeIntBitsToFloat() {
         float result = 123.0f;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Float.intBitsToFloat(mInt);
         }
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 cf76137..08dda53 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/FormatterPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -35,11 +35,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class FormatterPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeFormatter_NoFormatting() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a reasonably short string that doesn't actually need any formatting");
@@ -48,7 +48,7 @@
 
     @Test
     public void timeStringBuilder_NoFormatting() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             sb.append("this is a reasonably short string that doesn't actually need formatting");
@@ -58,7 +58,7 @@
     @Test
     public void timeFormatter_OneInt() {
         Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a reasonably short string that has an int %d in it", value);
@@ -69,7 +69,7 @@
     public void timeFormatter_OneIntArabic() {
         Locale arabic = new Locale("ar");
         Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format(arabic, "this is a reasonably short string that has an int %d in it", value);
@@ -78,7 +78,7 @@
 
     @Test
     public void timeStringBuilder_OneInt() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             sb.append("this is a reasonably short string that has an int ");
@@ -90,7 +90,7 @@
     @Test
     public void timeFormatter_OneHexInt() {
         Integer value = Integer.valueOf(1024); // We're not trying to benchmark boxing here.
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a reasonably short string that has an int %x in it", value);
@@ -99,7 +99,7 @@
 
     @Test
     public void timeStringBuilder_OneHexInt() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             sb.append("this is a reasonably short string that has an int ");
@@ -111,7 +111,7 @@
     @Test
     public void timeFormatter_OneFloat() {
         Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a reasonably short string that has a float %f in it", value);
@@ -121,7 +121,7 @@
     @Test
     public void timeFormatter_OneFloat_dot2f() {
         Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a reasonably short string that has a float %.2f in it", value);
@@ -131,7 +131,7 @@
     @Test
     public void timeFormatter_TwoFloats() {
         Float value = Float.valueOf(10.24f); // We're not trying to benchmark boxing here.
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a short string that has two floats %f and %f in it", value, value);
@@ -140,7 +140,7 @@
 
     @Test
     public void timeStringBuilder_OneFloat() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             sb.append("this is a reasonably short string that has a float ");
@@ -151,7 +151,7 @@
 
     @Test
     public void timeFormatter_OneString() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Formatter f = new Formatter();
             f.format("this is a reasonably short string that has a string %s in it", "hello");
@@ -160,7 +160,7 @@
 
     @Test
     public void timeStringBuilder_OneString() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             sb.append("this is a reasonably short string that has a string ");
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 833575a..a09ad80 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IdnPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class IdnPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeToUnicode() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             IDN.toASCII("fass.de");
             IDN.toASCII("faß.de");
@@ -51,7 +51,7 @@
 
     @Test
     public void timeToAscii() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             IDN.toUnicode("xn--fss-qla.de");
             IDN.toUnicode("xn--n00d.com");
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 1c901c8..be22814 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantDivisionPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class IntConstantDivisionPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeDivideIntByConstant2() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= 2;
         }
@@ -43,7 +43,7 @@
     @Test
     public void timeDivideIntByConstant8() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= 8;
         }
@@ -52,7 +52,7 @@
     @Test
     public void timeDivideIntByConstant10() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= 10;
         }
@@ -61,7 +61,7 @@
     @Test
     public void timeDivideIntByConstant100() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= 100;
         }
@@ -70,7 +70,7 @@
     @Test
     public void timeDivideIntByConstant100_HandOptimized() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = (int) ((0x51eb851fL * result) >>> 37);
         }
@@ -79,7 +79,7 @@
     @Test
     public void timeDivideIntByConstant2048() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= 2048;
         }
@@ -89,7 +89,7 @@
     public void timeDivideIntByVariable2() {
         int result = 1;
         int factor = 2;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= factor;
         }
@@ -99,7 +99,7 @@
     public void timeDivideIntByVariable10() {
         int result = 1;
         int factor = 10;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result /= factor;
         }
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 3d3af4c..4337c90 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantMultiplicationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class IntConstantMultiplicationPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeMultiplyIntByConstant6() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 6;
         }
@@ -43,7 +43,7 @@
     @Test
     public void timeMultiplyIntByConstant7() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 7;
         }
@@ -52,7 +52,7 @@
     @Test
     public void timeMultiplyIntByConstant8() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 8;
         }
@@ -61,7 +61,7 @@
     @Test
     public void timeMultiplyIntByConstant8_Shift() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result <<= 3;
         }
@@ -70,7 +70,7 @@
     @Test
     public void timeMultiplyIntByConstant10() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 10;
         }
@@ -79,7 +79,7 @@
     @Test
     public void timeMultiplyIntByConstant10_Shift() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = (result + (result << 2)) << 1;
         }
@@ -88,7 +88,7 @@
     @Test
     public void timeMultiplyIntByConstant2047() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 2047;
         }
@@ -97,7 +97,7 @@
     @Test
     public void timeMultiplyIntByConstant2048() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 2048;
         }
@@ -106,7 +106,7 @@
     @Test
     public void timeMultiplyIntByConstant2049() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= 2049;
         }
@@ -116,7 +116,7 @@
     public void timeMultiplyIntByVariable10() {
         int result = 1;
         int factor = 10;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= factor;
         }
@@ -126,7 +126,7 @@
     public void timeMultiplyIntByVariable8() {
         int result = 1;
         int factor = 8;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result *= factor;
         }
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 7c86633..1b6c502 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntConstantRemainderPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class IntConstantRemainderPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeRemainderIntByConstant2() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= 2;
         }
@@ -43,7 +43,7 @@
     @Test
     public void timeRemainderIntByConstant8() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= 8;
         }
@@ -52,7 +52,7 @@
     @Test
     public void timeRemainderIntByConstant10() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= 10;
         }
@@ -61,7 +61,7 @@
     @Test
     public void timeRemainderIntByConstant100() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= 100;
         }
@@ -70,7 +70,7 @@
     @Test
     public void timeRemainderIntByConstant2048() {
         int result = 1;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= 2048;
         }
@@ -80,7 +80,7 @@
     public void timeRemainderIntByVariable2() {
         int result = 1;
         int factor = 2;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= factor;
         }
@@ -90,7 +90,7 @@
     public void timeRemainderIntByVariable10() {
         int result = 1;
         int factor = 10;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result %= factor;
         }
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java
index e2a9dcc..170bb58 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntegerPerfTest.java
@@ -16,20 +16,20 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import org.junit.Rule;
 import org.junit.Test;
 
 public class IntegerPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeLongSignumBranch() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += signum1(-(++i));
             t += signum1(0);
@@ -41,7 +41,7 @@
     public void timeLongSignumBranchFree() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += signum2(-(++i));
             t += signum2(0);
@@ -61,7 +61,7 @@
     public void timeLongBitCount_BitSet() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += pop((long) ++i);
         }
@@ -89,7 +89,7 @@
     public void timeLongBitCount_2Int() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += pop2((long) ++i);
         }
@@ -105,7 +105,7 @@
     public void timeLongBitCount_Long() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += Long.bitCount((long) ++i);
         }
@@ -140,7 +140,7 @@
     public void timeNumberOfTrailingZerosHD() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += numberOfTrailingZerosHD(++i);
         }
@@ -150,7 +150,7 @@
     public void timeNumberOfTrailingZerosOL() {
         int t = 0;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             t += numberOfTrailingZerosOL(++i);
         }
@@ -163,7 +163,7 @@
                     "0", "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678"
                 };
         int t = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int j = 0; j < intStrings.length; ++j) {
                 t += Integer.valueOf(intStrings[j]);
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 669bfbf..0aa854e 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/IntegralToStringPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class IntegralToStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final int SMALL = 12;
     private static final int MEDIUM = 12345;
@@ -37,7 +37,7 @@
 
     @Test
     public void time_IntegerToString_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(SMALL);
         }
@@ -45,7 +45,7 @@
 
     @Test
     public void time_IntegerToString_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(MEDIUM);
         }
@@ -53,7 +53,7 @@
 
     @Test
     public void time_IntegerToString_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(LARGE);
         }
@@ -61,7 +61,7 @@
 
     @Test
     public void time_IntegerToString2_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(SMALL, 2);
         }
@@ -69,7 +69,7 @@
 
     @Test
     public void time_IntegerToString2_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(MEDIUM, 2);
         }
@@ -77,7 +77,7 @@
 
     @Test
     public void time_IntegerToString2_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(LARGE, 2);
         }
@@ -85,7 +85,7 @@
 
     @Test
     public void time_IntegerToString10_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(SMALL, 10);
         }
@@ -93,7 +93,7 @@
 
     @Test
     public void time_IntegerToString10_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(MEDIUM, 10);
         }
@@ -101,7 +101,7 @@
 
     @Test
     public void time_IntegerToString10_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(LARGE, 10);
         }
@@ -109,7 +109,7 @@
 
     @Test
     public void time_IntegerToString16_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(SMALL, 16);
         }
@@ -117,7 +117,7 @@
 
     @Test
     public void time_IntegerToString16_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(MEDIUM, 16);
         }
@@ -125,7 +125,7 @@
 
     @Test
     public void time_IntegerToString16_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toString(LARGE, 16);
         }
@@ -133,7 +133,7 @@
 
     @Test
     public void time_IntegerToBinaryString_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toBinaryString(SMALL);
         }
@@ -141,7 +141,7 @@
 
     @Test
     public void time_IntegerToBinaryString_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toBinaryString(MEDIUM);
         }
@@ -149,7 +149,7 @@
 
     @Test
     public void time_IntegerToBinaryString_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toBinaryString(LARGE);
         }
@@ -157,7 +157,7 @@
 
     @Test
     public void time_IntegerToHexString_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toHexString(SMALL);
         }
@@ -165,7 +165,7 @@
 
     @Test
     public void time_IntegerToHexString_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toHexString(MEDIUM);
         }
@@ -173,7 +173,7 @@
 
     @Test
     public void time_IntegerToHexString_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Integer.toHexString(LARGE);
         }
@@ -181,7 +181,7 @@
 
     @Test
     public void time_StringBuilder_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new StringBuilder().append(SMALL);
         }
@@ -189,7 +189,7 @@
 
     @Test
     public void time_StringBuilder_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new StringBuilder().append(MEDIUM);
         }
@@ -197,7 +197,7 @@
 
     @Test
     public void time_StringBuilder_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new StringBuilder().append(LARGE);
         }
@@ -205,7 +205,7 @@
 
     @Test
     public void time_Formatter_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%d", SMALL);
         }
@@ -213,7 +213,7 @@
 
     @Test
     public void time_Formatter_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%d", MEDIUM);
         }
@@ -221,7 +221,7 @@
 
     @Test
     public void time_Formatter_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%d", LARGE);
         }
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 cda8512..9b3d7a0 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/KeyPairGeneratorPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -36,7 +36,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class KeyPairGeneratorPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -78,7 +78,7 @@
     @Parameters(method = "getData")
     public void time(Algorithm algorithm, Implementation implementation) throws Exception {
         setUp(algorithm, implementation);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             KeyPair keyPair = mGenerator.generateKeyPair();
         }
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 8b062d3..1a9e19a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/LoopingBackwardsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -39,7 +39,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class LoopingBackwardsPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(new Object[][] {{2}, {20}, {2000}, {20000000}});
@@ -49,7 +49,7 @@
     @Parameters(method = "getData")
     public void timeForwards(int max) {
         int fake = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int j = 0; j < max; j++) {
                 fake += j;
@@ -61,7 +61,7 @@
     @Parameters(method = "getData")
     public void timeBackwards(int max) {
         int fake = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int j = max - 1; j >= 0; j--) {
                 fake += j;
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 bcf556c..a8a704c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MathPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class MathPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private final double mDouble = 1.2;
     private final float mFloat = 1.2f;
@@ -48,7 +48,7 @@
     @Test
     public void timeAbsD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.abs(mDouble);
         }
@@ -57,7 +57,7 @@
     @Test
     public void timeAbsF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.abs(mFloat);
         }
@@ -66,7 +66,7 @@
     @Test
     public void timeAbsI() {
         int result = mInt;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.abs(mInt);
         }
@@ -75,7 +75,7 @@
     @Test
     public void timeAbsL() {
         long result = mLong;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.abs(mLong);
         }
@@ -84,7 +84,7 @@
     @Test
     public void timeAcos() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.acos(mDouble);
         }
@@ -93,7 +93,7 @@
     @Test
     public void timeAsin() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.asin(mDouble);
         }
@@ -102,7 +102,7 @@
     @Test
     public void timeAtan() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.atan(mDouble);
         }
@@ -111,7 +111,7 @@
     @Test
     public void timeAtan2() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.atan2(3, 4);
         }
@@ -120,7 +120,7 @@
     @Test
     public void timeCbrt() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.cbrt(mDouble);
         }
@@ -129,7 +129,7 @@
     @Test
     public void timeCeil() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.ceil(mDouble);
         }
@@ -138,7 +138,7 @@
     @Test
     public void timeCopySignD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.copySign(mDouble, mDouble);
         }
@@ -147,7 +147,7 @@
     @Test
     public void timeCopySignF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.copySign(mFloat, mFloat);
         }
@@ -156,7 +156,7 @@
     @Test
     public void timeCopySignD_strict() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = StrictMath.copySign(mDouble, mDouble);
         }
@@ -165,7 +165,7 @@
     @Test
     public void timeCopySignF_strict() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = StrictMath.copySign(mFloat, mFloat);
         }
@@ -174,7 +174,7 @@
     @Test
     public void timeCos() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.cos(mDouble);
         }
@@ -183,7 +183,7 @@
     @Test
     public void timeCosh() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.cosh(mDouble);
         }
@@ -192,7 +192,7 @@
     @Test
     public void timeExp() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.exp(mDouble);
         }
@@ -201,7 +201,7 @@
     @Test
     public void timeExpm1() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.expm1(mDouble);
         }
@@ -210,7 +210,7 @@
     @Test
     public void timeFloor() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.floor(mDouble);
         }
@@ -219,7 +219,7 @@
     @Test
     public void timeGetExponentD() {
         int result = mInt;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.getExponent(mDouble);
         }
@@ -228,7 +228,7 @@
     @Test
     public void timeGetExponentF() {
         int result = mInt;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.getExponent(mFloat);
         }
@@ -237,7 +237,7 @@
     @Test
     public void timeHypot() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.hypot(mDouble, mDouble);
         }
@@ -246,7 +246,7 @@
     @Test
     public void timeIEEEremainder() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.IEEEremainder(mDouble, mDouble);
         }
@@ -255,7 +255,7 @@
     @Test
     public void timeLog() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.log(mDouble);
         }
@@ -264,7 +264,7 @@
     @Test
     public void timeLog10() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.log10(mDouble);
         }
@@ -273,7 +273,7 @@
     @Test
     public void timeLog1p() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.log1p(mDouble);
         }
@@ -282,7 +282,7 @@
     @Test
     public void timeMaxD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.max(mDouble, mDouble);
         }
@@ -291,7 +291,7 @@
     @Test
     public void timeMaxF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.max(mFloat, mFloat);
         }
@@ -300,7 +300,7 @@
     @Test
     public void timeMaxI() {
         int result = mInt;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.max(mInt, mInt);
         }
@@ -309,7 +309,7 @@
     @Test
     public void timeMaxL() {
         long result = mLong;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.max(mLong, mLong);
         }
@@ -318,7 +318,7 @@
     @Test
     public void timeMinD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.min(mDouble, mDouble);
         }
@@ -327,7 +327,7 @@
     @Test
     public void timeMinF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.min(mFloat, mFloat);
         }
@@ -336,7 +336,7 @@
     @Test
     public void timeMinI() {
         int result = mInt;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.min(mInt, mInt);
         }
@@ -345,7 +345,7 @@
     @Test
     public void timeMinL() {
         long result = mLong;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.min(mLong, mLong);
         }
@@ -354,7 +354,7 @@
     @Test
     public void timeNextAfterD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.nextAfter(mDouble, mDouble);
         }
@@ -363,7 +363,7 @@
     @Test
     public void timeNextAfterF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.nextAfter(mFloat, mFloat);
         }
@@ -372,7 +372,7 @@
     @Test
     public void timeNextUpD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.nextUp(mDouble);
         }
@@ -381,7 +381,7 @@
     @Test
     public void timeNextUpF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.nextUp(mFloat);
         }
@@ -390,7 +390,7 @@
     @Test
     public void timePow() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.pow(mDouble, mDouble);
         }
@@ -399,7 +399,7 @@
     @Test
     public void timeRandom() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.random();
         }
@@ -408,7 +408,7 @@
     @Test
     public void timeRint() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.rint(mDouble);
         }
@@ -417,7 +417,7 @@
     @Test
     public void timeRoundD() {
         long result = mLong;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.round(mDouble);
         }
@@ -426,7 +426,7 @@
     @Test
     public void timeRoundF() {
         int result = mInt;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.round(mFloat);
         }
@@ -435,7 +435,7 @@
     @Test
     public void timeScalbD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.scalb(mDouble, 5);
         }
@@ -444,7 +444,7 @@
     @Test
     public void timeScalbF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.scalb(mFloat, 5);
         }
@@ -453,7 +453,7 @@
     @Test
     public void timeSignumD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.signum(mDouble);
         }
@@ -462,7 +462,7 @@
     @Test
     public void timeSignumF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.signum(mFloat);
         }
@@ -471,7 +471,7 @@
     @Test
     public void timeSin() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.sin(mDouble);
         }
@@ -480,7 +480,7 @@
     @Test
     public void timeSinh() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.sinh(mDouble);
         }
@@ -489,7 +489,7 @@
     @Test
     public void timeSqrt() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.sqrt(mDouble);
         }
@@ -498,7 +498,7 @@
     @Test
     public void timeTan() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.tan(mDouble);
         }
@@ -507,7 +507,7 @@
     @Test
     public void timeTanh() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.tanh(mDouble);
         }
@@ -516,7 +516,7 @@
     @Test
     public void timeToDegrees() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.toDegrees(mDouble);
         }
@@ -525,7 +525,7 @@
     @Test
     public void timeToRadians() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.toRadians(mDouble);
         }
@@ -534,7 +534,7 @@
     @Test
     public void timeUlpD() {
         double result = mDouble;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.ulp(mDouble);
         }
@@ -543,7 +543,7 @@
     @Test
     public void timeUlpF() {
         float result = mFloat;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result = Math.ulp(mFloat);
         }
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 8325dae..6da9666 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -36,7 +36,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class MessageDigestPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -97,7 +97,7 @@
     @Test
     @Parameters(method = "getData")
     public void time(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             digest.update(DATA, 0, DATA_SIZE);
@@ -108,7 +108,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeLargeArray(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             digest.update(LARGE_DATA, 0, LARGE_DATA_SIZE);
@@ -119,7 +119,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeSmallChunkOfLargeArray(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             digest.update(LARGE_DATA, LARGE_DATA_SIZE / 2, DATA_SIZE);
@@ -130,7 +130,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeSmallByteBuffer(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             SMALL_BUFFER.position(0);
@@ -143,7 +143,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeSmallDirectByteBuffer(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             SMALL_DIRECT_BUFFER.position(0);
@@ -156,7 +156,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeLargeByteBuffer(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             LARGE_BUFFER.position(0);
@@ -169,7 +169,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeLargeDirectByteBuffer(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             LARGE_DIRECT_BUFFER.position(0);
@@ -182,7 +182,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeSmallChunkOfLargeByteBuffer(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             LARGE_BUFFER.position(LARGE_BUFFER.capacity() / 2);
@@ -195,7 +195,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeSmallChunkOfLargeDirectByteBuffer(Algorithm algorithm) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             MessageDigest digest = MessageDigest.getInstance(algorithm.toString(), mProvider);
             LARGE_DIRECT_BUFFER.position(LARGE_DIRECT_BUFFER.capacity() / 2);
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 266d42c..060d18f 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/MutableIntPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -35,7 +35,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public final class MutableIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     enum Kind {
         ARRAY() {
@@ -105,21 +105,21 @@
     @Test
     @Parameters(method = "getData")
     public void timeCreate(Kind kind) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         kind.timeCreate(state);
     }
 
     @Test
     @Parameters(method = "getData")
     public void timeIncrement(Kind kind) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         kind.timeIncrement(state);
     }
 
     @Test
     @Parameters(method = "getData")
     public void timeGet(Kind kind) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         kind.timeGet(state);
     }
 }
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 c2f84fb..7cb3b22 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,13 +32,13 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class NumberFormatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static Locale sLocale = Locale.getDefault(Locale.Category.FORMAT);
 
     @Test
     public void time_instantiation() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             NumberFormat.getInstance(sLocale);
         }
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 cdf0911..272b45a 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -36,12 +36,12 @@
 @LargeTest
 public class NumberFormatTrivialFormatLongPerfTest {
     @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeNumberFormatTrivialFormatLong() {
         NumberFormat nf = NumberFormat.getInstance(Locale.US);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             nf.format(1024L);
         }
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 51f47bb..c3a0966 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/PriorityQueuePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -39,7 +39,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class PriorityQueuePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -108,7 +108,7 @@
         // At most allow the queue to empty 10%.
         int resizingThreshold = queueSize / 10;
         int i = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             // Reset queue every so often. This will be called more often for smaller
             // queueSizes, but since a copy is linear, it will also cost proportionally
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 1f20cae..2ac56be 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/PropertyAccessPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public final class PropertyAccessPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private View mView = new View();
     private Method mSetX;
@@ -50,7 +50,7 @@
 
     @Test
     public void timeDirectSetter() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mView.mSetX(0.1f);
         }
@@ -58,7 +58,7 @@
 
     @Test
     public void timeDirectFieldSet() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mView.mX = 0.1f;
         }
@@ -66,7 +66,7 @@
 
     @Test
     public void timeDirectSetterAndBomXing() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float value = 0.1f;
             mView.mSetX(value);
@@ -75,7 +75,7 @@
 
     @Test
     public void timeDirectFieldSetAndBomXing() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float value = 0.1f;
             mView.mX = value;
@@ -84,7 +84,7 @@
 
     @Test
     public void timeReflectionSetterAndTwoBomXes() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mSetX.invoke(mView, 0.1f);
         }
@@ -92,7 +92,7 @@
 
     @Test
     public void timeReflectionSetterAndOneBomX() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mArgsBomX[0] = 0.1f;
             mSetX.invoke(mView, mArgsBomX);
@@ -101,7 +101,7 @@
 
     @Test
     public void timeReflectionFieldSet() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mX.setFloat(mView, 0.1f);
         }
@@ -109,7 +109,7 @@
 
     @Test
     public void timeGeneratedSetter() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mGeneratedSetter.setFloat(mView, 0.1f);
         }
@@ -117,7 +117,7 @@
 
     @Test
     public void timeGeneratedFieldSet() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mGeneratedField.setFloat(mView, 0.1f);
         }
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 0c16265..7ad0141 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ProviderPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,11 +34,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ProviderPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeStableProviders() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Cipher c = Cipher.getInstance("RSA");
         }
@@ -46,7 +46,7 @@
 
     @Test
     public void timeWithNewProvider() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Security.addProvider(new MockProvider());
             try {
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 5f1bfc2..c7b6cb5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/RandomPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,11 +32,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class RandomPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeNewRandom() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Random rng = new Random();
             rng.nextInt();
@@ -46,7 +46,7 @@
     @Test
     public void timeReusedRandom() throws Exception {
         Random rng = new Random();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             rng.nextInt();
         }
@@ -55,7 +55,7 @@
     @Test
     public void timeReusedSecureRandom() throws Exception {
         SecureRandom rng = new SecureRandom();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             rng.nextInt();
         }
@@ -63,7 +63,7 @@
 
     @Test
     public void timeNewSecureRandom() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             SecureRandom rng = new SecureRandom();
             rng.nextInt();
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 008c94c..44e5f22 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/RealToStringPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class RealToStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final float SMALL = -123.45f;
     private static final float MEDIUM = -123.45e8f;
@@ -37,7 +37,7 @@
 
     @Test
     public void timeFloat_toString_NaN() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(Float.NaN);
         }
@@ -45,7 +45,7 @@
 
     @Test
     public void timeFloat_toString_NEGATIVE_INFINITY() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(Float.NEGATIVE_INFINITY);
         }
@@ -53,7 +53,7 @@
 
     @Test
     public void timeFloat_toString_POSITIVE_INFINITY() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(Float.POSITIVE_INFINITY);
         }
@@ -61,7 +61,7 @@
 
     @Test
     public void timeFloat_toString_zero() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(0.0f);
         }
@@ -69,7 +69,7 @@
 
     @Test
     public void timeFloat_toString_minusZero() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(-0.0f);
         }
@@ -77,7 +77,7 @@
 
     @Test
     public void timeFloat_toString_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(SMALL);
         }
@@ -85,7 +85,7 @@
 
     @Test
     public void timeFloat_toString_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(MEDIUM);
         }
@@ -93,7 +93,7 @@
 
     @Test
     public void timeFloat_toString_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.toString(LARGE);
         }
@@ -101,7 +101,7 @@
 
     @Test
     public void timeStringBuilder_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new StringBuilder().append(SMALL);
         }
@@ -109,7 +109,7 @@
 
     @Test
     public void timeStringBuilder_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new StringBuilder().append(MEDIUM);
         }
@@ -117,7 +117,7 @@
 
     @Test
     public void timeStringBuilder_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new StringBuilder().append(LARGE);
         }
@@ -125,7 +125,7 @@
 
     @Test
     public void timeFormatter_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%f", SMALL);
         }
@@ -133,7 +133,7 @@
 
     @Test
     public void timeFormatter_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%f", MEDIUM);
         }
@@ -141,7 +141,7 @@
 
     @Test
     public void timeFormatter_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%f", LARGE);
         }
@@ -149,7 +149,7 @@
 
     @Test
     public void timeFormatter_dot2f_small() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%.2f", SMALL);
         }
@@ -157,7 +157,7 @@
 
     @Test
     public void timeFormatter_dot2f_medium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%.2f", MEDIUM);
         }
@@ -165,7 +165,7 @@
 
     @Test
     public void timeFormatter_dot2f_large() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             String.format("%.2f", LARGE);
         }
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 45b623d..6e00b1083 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ReflectionPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,12 +33,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectionPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeObject_getClass() throws Exception {
         C c = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             c.getClass();
         }
@@ -47,7 +47,7 @@
     @Test
     public void timeClass_getField() throws Exception {
         Class<?> klass = C.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.getField("f");
         }
@@ -56,7 +56,7 @@
     @Test
     public void timeClass_getDeclaredField() throws Exception {
         Class<?> klass = C.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.getDeclaredField("f");
         }
@@ -65,7 +65,7 @@
     @Test
     public void timeClass_getConstructor() throws Exception {
         Class<?> klass = C.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.getConstructor();
         }
@@ -75,7 +75,7 @@
     public void timeClass_newInstance() throws Exception {
         Class<?> klass = C.class;
         Constructor constructor = klass.getConstructor();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             constructor.newInstance();
         }
@@ -84,7 +84,7 @@
     @Test
     public void timeClass_getMethod() throws Exception {
         Class<?> klass = C.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.getMethod("m");
         }
@@ -93,7 +93,7 @@
     @Test
     public void timeClass_getDeclaredMethod() throws Exception {
         Class<?> klass = C.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.getDeclaredMethod("m");
         }
@@ -104,7 +104,7 @@
         Class<?> klass = C.class;
         Field f = klass.getDeclaredField("f");
         C instance = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             f.setInt(instance, 1);
         }
@@ -115,7 +115,7 @@
         Class<?> klass = C.class;
         Field f = klass.getDeclaredField("f");
         C instance = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             f.getInt(instance);
         }
@@ -126,7 +126,7 @@
         Class<?> klass = C.class;
         Method m = klass.getDeclaredMethod("m");
         C instance = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             m.invoke(instance);
         }
@@ -136,7 +136,7 @@
     public void timeMethod_invokeStaticV() throws Exception {
         Class<?> klass = C.class;
         Method m = klass.getDeclaredMethod("sm");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             m.invoke(null);
         }
@@ -147,7 +147,7 @@
         Class<?> klass = C.class;
         Method m = klass.getDeclaredMethod("setField", int.class);
         C instance = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             m.invoke(instance, 1);
         }
@@ -159,7 +159,7 @@
         Method m = klass.getDeclaredMethod("setField", int.class);
         C instance = new C();
         Integer one = Integer.valueOf(1);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             m.invoke(instance, one);
         }
@@ -169,7 +169,7 @@
     public void timeMethod_invokeStaticI() throws Exception {
         Class<?> klass = C.class;
         Method m = klass.getDeclaredMethod("setStaticField", int.class);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             m.invoke(null, 1);
         }
@@ -180,7 +180,7 @@
         Class<?> klass = C.class;
         Method m = klass.getDeclaredMethod("setStaticField", int.class);
         Integer one = Integer.valueOf(1);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             m.invoke(null, one);
         }
@@ -189,7 +189,7 @@
     @Test
     public void timeRegularMethodInvocation() throws Exception {
         C instance = new C();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             instance.setField(1);
         }
@@ -197,7 +197,7 @@
 
     @Test
     public void timeRegularConstructor() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             new C();
         }
@@ -206,7 +206,7 @@
     @Test
     public void timeClass_classNewInstance() throws Exception {
         Class<?> klass = C.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.newInstance();
         }
@@ -216,7 +216,7 @@
     public void timeClass_isInstance() throws Exception {
         D d = new D();
         Class<?> klass = IC.class;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             klass.isInstance(d);
         }
@@ -224,7 +224,7 @@
 
     @Test
     public void timeGetInstanceField() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             // TODO: Write a test script that generates both the classes we're
             // reflecting on and the test case for each of its fields.
@@ -234,7 +234,7 @@
 
     @Test
     public void timeGetStaticField() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             R.class.getField("WEEK_NUMBER_COLOR");
         }
@@ -242,7 +242,7 @@
 
     @Test
     public void timeGetInterfaceStaticField() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             F.class.getField("SF");
         }
@@ -250,7 +250,7 @@
 
     @Test
     public void timeGetSuperClassField() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             G.class.getField("f");
         }
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 da69f9f..5a9b5c3 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLLoopbackPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -35,11 +35,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class SSLLoopbackPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void time() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TestSSLContext context =
                     TestSSLContext.create(TestKeyStore.getClient(), TestKeyStore.getServer());
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 9f2c312..6d48cf2 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SSLSocketFactoryPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class SSLSocketFactoryPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void time() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             SSLSocketFactory.getDefault();
         }
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 7c60c05..8641629 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SchemePrefixPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -37,7 +37,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public final class SchemePrefixPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     enum Strategy {
         JAVA() {
@@ -94,7 +94,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeSchemePrefix(Strategy strategy) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             strategy.execute("http://android.com");
         }
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 1812983..afd1191 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SerializationPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -37,7 +37,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class SerializationPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static byte[] bytes(Object o) throws Exception {
         ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
@@ -110,7 +110,7 @@
     public void timeWriteNoObjects() throws Exception {
         ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
         ObjectOutputStream out = new ObjectOutputStream(baos);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             out.reset();
             baos.reset();
@@ -121,7 +121,7 @@
     private void readSingleObject(Object object) throws Exception {
         byte[] bytes = bytes(object);
         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ObjectInputStream in = new ObjectInputStream(bais);
             in.readObject();
@@ -133,7 +133,7 @@
     private void writeSingleObject(Object o) throws Exception {
         ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
         ObjectOutputStream out = new ObjectOutputStream(baos);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             out.writeObject(o);
             out.reset();
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 34e9bfb..6c26133 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SignaturePerfTest.java
@@ -15,8 +15,8 @@
  */
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -41,7 +41,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class SignaturePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -117,7 +117,7 @@
     @Parameters(method = "getData")
     public void timeSign(Algorithm algorithm, Implementation implementation) throws Exception {
         setUp(algorithm);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Signature signer;
             switch (implementation) {
@@ -140,7 +140,7 @@
     @Parameters(method = "getData")
     public void timeVerify(Algorithm algorithm, Implementation implementation) throws Exception {
         setUp(algorithm);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Signature verifier;
             switch (implementation) {
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 2fe6798..274b51f 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/SimpleDateFormatPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -37,11 +37,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class SimpleDateFormatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void time_createFormatWithTimeZone() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
         }
@@ -50,7 +50,7 @@
     @Test
     public void time_parseWithTimeZoneShort() throws ParseException {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             sdf.parse("2000.01.01 PST");
         }
@@ -59,7 +59,7 @@
     @Test
     public void time_parseWithTimeZoneLong() throws ParseException {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             sdf.parse("2000.01.01 Pacific Standard Time");
         }
@@ -68,7 +68,7 @@
     @Test
     public void time_parseWithoutTimeZone() throws ParseException {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             sdf.parse("2000.01.01");
         }
@@ -76,7 +76,7 @@
 
     @Test
     public void time_createAndParseWithTimeZoneShort() throws ParseException {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
             sdf.parse("2000.01.01 PST");
@@ -85,7 +85,7 @@
 
     @Test
     public void time_createAndParseWithTimeZoneLong() throws ParseException {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
             sdf.parse("2000.01.01 Pacific Standard Time");
@@ -95,7 +95,7 @@
     @Test
     public void time_formatWithTimeZoneShort() {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd z");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             sdf.format(new Date());
         }
@@ -104,7 +104,7 @@
     @Test
     public void time_formatWithTimeZoneLong() {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd zzzz");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             sdf.format(new Date());
         }
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 fbe3cef..b4c427b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StrictMathPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -33,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StrictMathPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private final double mDouble = 1.2;
     private final float mFloat = 1.2f;
@@ -74,7 +74,7 @@
 
     @Test
     public void timeAbsD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.abs(mDouble);
         }
@@ -82,7 +82,7 @@
 
     @Test
     public void timeAbsF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.abs(mFloat);
         }
@@ -90,7 +90,7 @@
 
     @Test
     public void timeAbsI() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.abs(mInt);
         }
@@ -98,7 +98,7 @@
 
     @Test
     public void timeAbsL() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.abs(mLong);
         }
@@ -106,7 +106,7 @@
 
     @Test
     public void timeAcos() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.acos(mDouble);
         }
@@ -114,7 +114,7 @@
 
     @Test
     public void timeAsin() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.asin(mDouble);
         }
@@ -122,7 +122,7 @@
 
     @Test
     public void timeAtan() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.atan(mDouble);
         }
@@ -130,7 +130,7 @@
 
     @Test
     public void timeAtan2() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.atan2(3, 4);
         }
@@ -138,7 +138,7 @@
 
     @Test
     public void timeCbrt() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.cbrt(mDouble);
         }
@@ -146,7 +146,7 @@
 
     @Test
     public void timeCeilOverInterestingValues() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < CEIL_DOUBLES.length; ++i) {
                 StrictMath.ceil(CEIL_DOUBLES[i]);
@@ -156,7 +156,7 @@
 
     @Test
     public void timeCopySignD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.copySign(mDouble, mDouble);
         }
@@ -164,7 +164,7 @@
 
     @Test
     public void timeCopySignF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.copySign(mFloat, mFloat);
         }
@@ -172,7 +172,7 @@
 
     @Test
     public void timeCos() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.cos(mDouble);
         }
@@ -180,7 +180,7 @@
 
     @Test
     public void timeCosh() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.cosh(mDouble);
         }
@@ -188,7 +188,7 @@
 
     @Test
     public void timeExp() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.exp(mDouble);
         }
@@ -196,7 +196,7 @@
 
     @Test
     public void timeExpm1() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.expm1(mDouble);
         }
@@ -204,7 +204,7 @@
 
     @Test
     public void timeFloorOverInterestingValues() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < FLOOR_DOUBLES.length; ++i) {
                 StrictMath.floor(FLOOR_DOUBLES[i]);
@@ -214,7 +214,7 @@
 
     @Test
     public void timeGetExponentD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.getExponent(mDouble);
         }
@@ -222,7 +222,7 @@
 
     @Test
     public void timeGetExponentF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.getExponent(mFloat);
         }
@@ -230,7 +230,7 @@
 
     @Test
     public void timeHypot() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.hypot(mDouble, mDouble);
         }
@@ -238,7 +238,7 @@
 
     @Test
     public void timeIEEEremainder() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.IEEEremainder(mDouble, mDouble);
         }
@@ -246,7 +246,7 @@
 
     @Test
     public void timeLog() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.log(mDouble);
         }
@@ -254,7 +254,7 @@
 
     @Test
     public void timeLog10() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.log10(mDouble);
         }
@@ -262,7 +262,7 @@
 
     @Test
     public void timeLog1p() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.log1p(mDouble);
         }
@@ -270,7 +270,7 @@
 
     @Test
     public void timeMaxD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.max(mDouble, mDouble);
         }
@@ -278,7 +278,7 @@
 
     @Test
     public void timeMaxF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.max(mFloat, mFloat);
         }
@@ -286,7 +286,7 @@
 
     @Test
     public void timeMaxI() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.max(mInt, mInt);
         }
@@ -294,7 +294,7 @@
 
     @Test
     public void timeMaxL() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.max(mLong, mLong);
         }
@@ -302,7 +302,7 @@
 
     @Test
     public void timeMinD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.min(mDouble, mDouble);
         }
@@ -310,7 +310,7 @@
 
     @Test
     public void timeMinF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.min(mFloat, mFloat);
         }
@@ -318,7 +318,7 @@
 
     @Test
     public void timeMinI() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.min(mInt, mInt);
         }
@@ -326,7 +326,7 @@
 
     @Test
     public void timeMinL() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.min(mLong, mLong);
         }
@@ -334,7 +334,7 @@
 
     @Test
     public void timeNextAfterD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.nextAfter(mDouble, mDouble);
         }
@@ -342,7 +342,7 @@
 
     @Test
     public void timeNextAfterF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.nextAfter(mFloat, mFloat);
         }
@@ -350,7 +350,7 @@
 
     @Test
     public void timeNextUpD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.nextUp(mDouble);
         }
@@ -358,7 +358,7 @@
 
     @Test
     public void timeNextUpF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.nextUp(mFloat);
         }
@@ -366,7 +366,7 @@
 
     @Test
     public void timePow() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.pow(mDouble, mDouble);
         }
@@ -374,7 +374,7 @@
 
     @Test
     public void timeRandom() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.random();
         }
@@ -382,7 +382,7 @@
 
     @Test
     public void timeRint() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.rint(mDouble);
         }
@@ -390,7 +390,7 @@
 
     @Test
     public void timeRoundD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.round(mDouble);
         }
@@ -398,7 +398,7 @@
 
     @Test
     public void timeRoundF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.round(mFloat);
         }
@@ -406,7 +406,7 @@
 
     @Test
     public void timeScalbD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.scalb(mDouble, 5);
         }
@@ -414,7 +414,7 @@
 
     @Test
     public void timeScalbF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.scalb(mFloat, 5);
         }
@@ -422,7 +422,7 @@
 
     @Test
     public void timeSignumD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.signum(mDouble);
         }
@@ -430,7 +430,7 @@
 
     @Test
     public void timeSignumF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.signum(mFloat);
         }
@@ -438,7 +438,7 @@
 
     @Test
     public void timeSin() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.sin(mDouble);
         }
@@ -446,7 +446,7 @@
 
     @Test
     public void timeSinh() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.sinh(mDouble);
         }
@@ -454,7 +454,7 @@
 
     @Test
     public void timeSqrt() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.sqrt(mDouble);
         }
@@ -462,7 +462,7 @@
 
     @Test
     public void timeTan() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.tan(mDouble);
         }
@@ -470,7 +470,7 @@
 
     @Test
     public void timeTanh() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.tanh(mDouble);
         }
@@ -478,7 +478,7 @@
 
     @Test
     public void timeToDegrees() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.toDegrees(mDouble);
         }
@@ -486,7 +486,7 @@
 
     @Test
     public void timeToRadians() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.toRadians(mDouble);
         }
@@ -494,7 +494,7 @@
 
     @Test
     public void timeUlpD() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.ulp(mDouble);
         }
@@ -502,7 +502,7 @@
 
     @Test
     public void timeUlpF() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StrictMath.ulp(mFloat);
         }
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 0155154..2235cc5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,13 +30,13 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringBuilderPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public int mLength = 100;
 
     @Test
     public void timeAppendBoolean() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -47,7 +47,7 @@
 
     @Test
     public void timeAppendChar() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -59,7 +59,7 @@
     @Test
     public void timeAppendCharArray() {
         char[] chars = "chars".toCharArray();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -71,7 +71,7 @@
     @Test
     public void timeAppendCharSequence() {
         CharSequence cs = "chars";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -83,7 +83,7 @@
     @Test
     public void timeAppendSubCharSequence() {
         CharSequence cs = "chars";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -95,7 +95,7 @@
     @Test
     public void timeAppendDouble() {
         double d = 1.2;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -107,7 +107,7 @@
     @Test
     public void timeAppendFloat() {
         float f = 1.2f;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -119,7 +119,7 @@
     @Test
     public void timeAppendInt() {
         int n = 123;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -131,7 +131,7 @@
     @Test
     public void timeAppendLong() {
         long l = 123;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -150,7 +150,7 @@
                         return "constant";
                     }
                 };
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
@@ -162,7 +162,7 @@
     @Test
     public void timeAppendString() {
         String s = "chars";
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             StringBuilder sb = new StringBuilder();
             for (int j = 0; j < mLength; ++j) {
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 5533745..9ab5000 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringEqualsPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,7 +38,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringEqualsPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private final String mLong1 =
             "Ahead-of-time compilation is possible as the compiler may just convert an instruction"
@@ -226,7 +226,7 @@
     // Benchmark cases of String.equals(null)
     @Test
     public void timeEqualsNull() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mMediumStrings.length; i++) {
                 mMediumStrings[i][0].equals(null);
@@ -237,7 +237,7 @@
     // Benchmark cases with very short (<5 character) Strings
     @Test
     public void timeEqualsShort() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mShortStrings.length; i++) {
                 mShortStrings[i][0].equals(mShortStrings[i][1]);
@@ -248,7 +248,7 @@
     // Benchmark cases with medium length (10-15 character) Strings
     @Test
     public void timeEqualsMedium() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mMediumStrings.length; i++) {
                 mMediumStrings[i][0].equals(mMediumStrings[i][1]);
@@ -259,7 +259,7 @@
     // Benchmark cases with long (>100 character) Strings
     @Test
     public void timeEqualsLong() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mLongStrings.length; i++) {
                 mLongStrings[i][0].equals(mLongStrings[i][1]);
@@ -270,7 +270,7 @@
     // Benchmark cases with very long (>1000 character) Strings
     @Test
     public void timeEqualsVeryLong() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mVeryLongStrings.length; i++) {
                 mVeryLongStrings[i][0].equals(mVeryLongStrings[i][1]);
@@ -281,7 +281,7 @@
     // Benchmark cases with non-word aligned Strings
     @Test
     public void timeEqualsNonWordAligned() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mNonalignedStrings.length; i++) {
                 mNonalignedStrings[i][0].equals(mNonalignedStrings[i][1]);
@@ -292,7 +292,7 @@
     // Benchmark cases with slight differences in the endings
     @Test
     public void timeEqualsEnd() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mEndStrings.length; i++) {
                 mEndStrings[i][0].equals(mEndStrings[i][1]);
@@ -303,7 +303,7 @@
     // Benchmark cases of comparing a string to a non-string object
     @Test
     public void timeEqualsNonString() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             for (int i = 0; i < mMediumStrings.length; i++) {
                 mMediumStrings[i][0].equals(mObjects[i]);
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 a5662b0..b1e749c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringIsEmptyPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringIsEmptyPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeIsEmpty_NonEmpty() {
         boolean result = true;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result &= !("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".isEmpty());
         }
@@ -44,7 +44,7 @@
     @Test
     public void timeIsEmpty_Empty() {
         boolean result = true;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result &= ("".isEmpty());
         }
@@ -54,7 +54,7 @@
     @Test
     public void timeLengthEqualsZero() {
         boolean result = true;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result &= !("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".length() == 0);
         }
@@ -64,7 +64,7 @@
     @Test
     public void timeEqualsEmpty() {
         boolean result = true;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             result &= !"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".equals("");
         }
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 41e64f2..9e57591 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringLengthPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,12 +29,12 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringLengthPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeLength() {
         int length = 0;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             length = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".length();
         }
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 2cd2a09..a80514c 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -34,7 +34,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class StringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     enum StringLengths {
         EMPTY(""),
@@ -69,7 +69,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeHashCode(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.hashCode();
         }
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 219dccf..78ae395 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplaceAllPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -34,7 +34,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class StringReplaceAllPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     // NOTE: These estimates of MOVEABLE / NON_MOVEABLE are based on a knowledge of
     // ART implementation details. They make a difference here because JNI calls related
@@ -86,7 +86,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceAllTrivialPatternNonExistent(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replaceAll("fish", "0");
         }
@@ -95,7 +95,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceTrivialPatternAllRepeated(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replaceAll("jklm", "0");
         }
@@ -104,7 +104,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceAllTrivialPatternSingleOccurrence(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replaceAll("qrst", "0");
         }
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 d6fef5e..73911c7 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringReplacePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -34,7 +34,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class StringReplacePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     enum StringLengths {
         EMPTY(""),
@@ -80,7 +80,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceCharNonExistent(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replace('z', '0');
         }
@@ -89,7 +89,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceCharRepeated(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replace('a', '0');
         }
@@ -98,7 +98,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceSingleChar(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replace('q', '0');
         }
@@ -107,7 +107,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceSequenceNonExistent(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replace("fish", "0");
         }
@@ -116,7 +116,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceSequenceRepeated(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replace("jklm", "0");
         }
@@ -125,7 +125,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeReplaceSingleSequence(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.replace("qrst", "0");
         }
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 9d0ec2f..1539271 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringSplitPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StringSplitPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeStringSplitComma() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             "this,is,a,simple,example".split(",");
         }
@@ -43,7 +43,7 @@
 
     @Test
     public void timeStringSplitLiteralDot() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             "this.is.a.simple.example".split("\\.");
         }
@@ -51,7 +51,7 @@
 
     @Test
     public void timeStringSplitNewline() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             "this\nis\na\nsimple\nexample\n".split("\n");
         }
@@ -60,7 +60,7 @@
     @Test
     public void timePatternSplitComma() {
         Pattern p = Pattern.compile(",");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             p.split("this,is,a,simple,example");
         }
@@ -69,7 +69,7 @@
     @Test
     public void timePatternSplitLiteralDot() {
         Pattern p = Pattern.compile("\\.");
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             p.split("this.is.a.simple.example");
         }
@@ -77,7 +77,7 @@
 
     @Test
     public void timeStringSplitHard() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             "this,is,a,harder,example".split("[,]");
         }
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 11950b7..0d5e62b 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToBytesPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -35,7 +35,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class StringToBytesPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     enum StringLengths {
         EMPTY(""),
@@ -89,7 +89,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeGetBytesUtf8(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.getBytes(StandardCharsets.UTF_8);
         }
@@ -98,7 +98,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeGetBytesIso88591(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.getBytes(StandardCharsets.ISO_8859_1);
         }
@@ -107,7 +107,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeGetBytesAscii(StringLengths stringLengths) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             stringLengths.mValue.getBytes(StandardCharsets.US_ASCII);
         }
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 4b27a16..ecdf809 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/StringToRealPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -34,7 +34,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public class StringToRealPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -53,7 +53,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeFloat_parseFloat(String string) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Float.parseFloat(string);
         }
@@ -62,7 +62,7 @@
     @Test
     @Parameters(method = "getData")
     public void timeDouble_parseDouble(String string) {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             Double.parseDouble(string);
         }
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 0ab012d..2b2a6b5 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ThreadLocalPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -29,7 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ThreadLocalPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private static final ThreadLocal<char[]> BUFFER =
             new ThreadLocal<char[]>() {
@@ -41,7 +41,7 @@
 
     @Test
     public void timeThreadLocal_get() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             BUFFER.get();
         }
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 ddf410e..6eb8fcc 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/TimeZonePerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,11 +31,11 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class TimeZonePerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Test
     public void timeTimeZone_getDefault() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TimeZone.getDefault();
         }
@@ -43,7 +43,7 @@
 
     @Test
     public void timeTimeZone_getTimeZoneUTC() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TimeZone.getTimeZone("UTC");
         }
@@ -52,7 +52,7 @@
     @Test
     public void timeTimeZone_getTimeZone_default() throws Exception {
         String defaultId = TimeZone.getDefault().getID();
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TimeZone.getTimeZone(defaultId);
         }
@@ -61,7 +61,7 @@
     // A time zone with relatively few transitions.
     @Test
     public void timeTimeZone_getTimeZone_America_Caracas() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TimeZone.getTimeZone("America/Caracas");
         }
@@ -70,7 +70,7 @@
     // A time zone with a lot of transitions.
     @Test
     public void timeTimeZone_getTimeZone_America_Santiago() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TimeZone.getTimeZone("America/Santiago");
         }
@@ -78,7 +78,7 @@
 
     @Test
     public void timeTimeZone_getTimeZone_GMT_plus_10() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             TimeZone.getTimeZone("GMT+10");
         }
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 a38763b..288c646 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/XMLEntitiesPerfTest.java
@@ -16,8 +16,8 @@
 
 package android.libcore.regression;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 
@@ -42,7 +42,7 @@
 @RunWith(JUnitParamsRunner.class)
 @LargeTest
 public final class XMLEntitiesPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     public static Collection<Object[]> getData() {
         return Arrays.asList(
@@ -85,7 +85,7 @@
     @Parameters(method = "getData")
     public void timeXmlParser(int length, float entityFraction) throws Exception {
         setUp(length, entityFraction);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             XmlPullParser parser = mXmlPullParserFactory.newPullParser();
             parser.setInput(new StringReader(mXml));
@@ -99,7 +99,7 @@
     @Parameters(method = "getData")
     public void timeDocumentBuilder(int length, float entityFraction) throws Exception {
         setUp(length, entityFraction);
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             DocumentBuilder documentBuilder = mDocumentBuilderFactory.newDocumentBuilder();
             documentBuilder.parse(new InputSource(new StringReader(mXml)));
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 4076c9d..003c957 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectGetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     int mValue;
 
@@ -47,7 +42,7 @@
     @Test
     public void run() throws Throwable {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mField.getInt(this);
             x = (int) mField.getInt(this);
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 2c65dd4..4f21618 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectGetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     String mValue;
 
@@ -47,7 +42,7 @@
     @Test
     public void run() throws Throwable {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mField.get(this);
             x = (String) mField.get(this);
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 dcd25db..210014a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectGetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     static int sValue;
 
@@ -47,7 +42,7 @@
     @Test
     public void run() throws Throwable {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mField.getInt(null);
             x = (int) mField.getInt(null);
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 c938a4c..22c6827 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectGetStaticFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectGetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     static String sValue;
 
@@ -47,7 +42,7 @@
     @Test
     public void run() throws Throwable {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mField.get(null);
             x = (String) mField.get(null);
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 618e1b5..5b39109 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectSetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     int mValue;
 
@@ -46,7 +41,7 @@
 
     @Test
     public void run() throws Throwable {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.setInt(this, 42);
             mField.setInt(this, 42);
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 8c2e3ca..883e8a7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectSetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     String mValue;
 
@@ -46,7 +41,7 @@
 
     @Test
     public void run() throws Throwable {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.set(this, "qwerty");
             mField.set(this, "qwerty");
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 e888cc68..50bc85c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianIntPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectSetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     static int sValue;
 
@@ -46,7 +41,7 @@
 
     @Test
     public void run() throws Throwable {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.setInt(null, 42);
             mField.setInt(null, 42);
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 7016611..13fa2bf 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/ReflectSetStaticFieldLittleEndianStringPerfTest.java
@@ -13,30 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-
 import java.lang.reflect.Field;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ReflectSetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     static String sValue;
 
@@ -46,7 +41,7 @@
 
     @Test
     public void run() throws Throwable {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mField.set(null, "qwerty");
             mField.set(null, "qwerty");
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 65c82cc..85c9bae9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.compareAndExchangeAcquire(this, mField, ~42);
             x = (int) mVh.compareAndExchangeAcquire(this, mField, 42);
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 a350b61..2b8f430 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeAcquireFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.compareAndExchangeAcquire(this, mField, null);
             x = (String) mVh.compareAndExchangeAcquire(this, mField, "qwerty");
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 34f596e..246fa43 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.compareAndExchangeAcquire(sField, ~42);
             x = (int) mVh.compareAndExchangeAcquire(sField, 42);
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 2216d7b..d12ffae 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
 
-    public VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest() throws Throwable {
+    public VarHandleCompareandexchangeAcquireStaticFieldLittleEndianStringPerfTest()
+            throws Throwable {
         mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
     }
 
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.compareAndExchangeAcquire(sField, null);
             x = (String) mVh.compareAndExchangeAcquire(sField, "qwerty");
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 bda551f..5ced115 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.compareAndExchange(this, mField, ~42);
             x = (int) mVh.compareAndExchange(this, mField, 42);
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 f4d7893..b955d50 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.compareAndExchange(this, mField, null);
             x = (String) mVh.compareAndExchange(this, mField, "qwerty");
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 f438087..601ff34 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.compareAndExchangeRelease(this, mField, ~42);
             x = (int) mVh.compareAndExchangeRelease(this, mField, 42);
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 78df5c0..0e567f9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeReleaseFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.compareAndExchangeRelease(this, mField, null);
             x = (String) mVh.compareAndExchangeRelease(this, mField, "qwerty");
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 f45cc62..6be2870 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.compareAndExchangeRelease(sField, ~42);
             x = (int) mVh.compareAndExchangeRelease(sField, 42);
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 08aa7e2..84c186b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
 
-    public VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest() throws Throwable {
+    public VarHandleCompareandexchangeReleaseStaticFieldLittleEndianStringPerfTest()
+            throws Throwable {
         mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
     }
 
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.compareAndExchangeRelease(sField, null);
             x = (String) mVh.compareAndExchangeRelease(sField, "qwerty");
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 5d4b2e0..b093234 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.compareAndExchange(sField, ~42);
             x = (int) mVh.compareAndExchange(sField, 42);
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 ba4f2c8..0d2037b4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandexchangeStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.compareAndExchange(sField, null);
             x = (String) mVh.compareAndExchange(sField, "qwerty");
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 7fca450..ee31973 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandsetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.compareAndSet(this, mField, ~42);
             success = mVh.compareAndSet(this, mField, 42);
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 7eb7ac0..0571fef 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandsetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.compareAndSet(this, mField, null);
             success = mVh.compareAndSet(this, mField, "qwerty");
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 ddfd407..f619dab 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandsetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.compareAndSet(sField, ~42);
             success = mVh.compareAndSet(sField, 42);
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 f1f3968..fc443fa 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleCompareandsetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.compareAndSet(sField, null);
             success = mVh.compareAndSet(sField, "qwerty");
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 09127c4..bf3d58b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAcquire(this);
             x = (int) mVh.getAcquire(this);
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 87be4a6..1f4bc31 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetAcquireFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAcquire(this);
             x = (String) mVh.getAcquire(this);
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 5d5fc11..2085552 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAcquire();
             x = (int) mVh.getAcquire();
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 c7034b8..d9c7d7b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetAcquireStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAcquire();
             x = (String) mVh.getAcquire();
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 f22865b..acd2533 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,9 +33,9 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetArrayLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int ELEMENT_VALUE = 42;
-    int[] mArray = { ELEMENT_VALUE };
+    int[] mArray = {ELEMENT_VALUE};
     VarHandle mVh;
 
     public VarHandleGetArrayLittleEndianIntPerfTest() throws Throwable {
@@ -55,7 +54,7 @@
     public void run() {
         int[] a = mArray;
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.get(a, 0);
             x = (int) mVh.get(a, 0);
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 fdb9e84..de9944a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetArrayLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,9 +33,9 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetArrayLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String ELEMENT_VALUE = "qwerty";
-    String[] mArray = { ELEMENT_VALUE };
+    String[] mArray = {ELEMENT_VALUE};
     VarHandle mVh;
 
     public VarHandleGetArrayLittleEndianStringPerfTest() throws Throwable {
@@ -55,7 +54,7 @@
     public void run() {
         String[] a = mArray;
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.get(a, 0);
             x = (String) mVh.get(a, 0);
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 347b0cf..a863929 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewBigEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -30,22 +29,22 @@
 
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
 import java.nio.ByteOrder;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetByteArrayViewBigEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int VALUE = 42;
-    byte[] mArray1 = { (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE };
-    byte[] mArray2 = { (byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE };
+    byte[] mArray1 = {
+        (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE
+    };
+    byte[] mArray2 = {(byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE};
     VarHandle mVh;
 
     public VarHandleGetByteArrayViewBigEndianIntPerfTest() throws Throwable {
         mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
-  }
+    }
 
     @Before
     public void setup() {
@@ -59,7 +58,7 @@
     public void run() {
         byte[] a = mArray1;
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.get(a, 0);
             x = (int) mVh.get(a, 0);
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 dedc94f..4999b9b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetByteArrayViewLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -30,22 +29,22 @@
 
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
 import java.nio.ByteOrder;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetByteArrayViewLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int VALUE = 42;
-    byte[] mArray1 = { (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24) };
-    byte[] mArray2 = { (byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24) };
+    byte[] mArray1 = {
+        (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24)
+    };
+    byte[] mArray2 = {(byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24)};
     VarHandle mVh;
 
     public VarHandleGetByteArrayViewLittleEndianIntPerfTest() throws Throwable {
         mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
-  }
+    }
 
     @Before
     public void setup() {
@@ -59,7 +58,7 @@
     public void run() {
         byte[] a = mArray1;
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.get(a, 0);
             x = (int) mVh.get(a, 0);
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 3f0f624..ee80a6f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.get(this);
             x = (int) mVh.get(this);
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 9db6328..ec29f7a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.get(this);
             x = (String) mVh.get(this);
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 17b74a8..ee6a669 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetOpaqueFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getOpaque(this);
             x = (int) mVh.getOpaque(this);
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 5df1380..1702b84 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetOpaqueFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getOpaque(this);
             x = (String) mVh.getOpaque(this);
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 f656ef2..514ddb9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetOpaqueStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getOpaque();
             x = (int) mVh.getOpaque();
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 1087df3..fbcee69 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetOpaqueStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getOpaque();
             x = (String) mVh.getOpaque();
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 0043451..2c56588 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.get();
             x = (int) mVh.get();
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 0162637..8fce69e 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.get();
             x = (String) mVh.get();
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 b0c4631..ef530607 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetVolatileFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getVolatile(this);
             x = (int) mVh.getVolatile(this);
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 5cbbc08..64c0898 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetVolatileFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getVolatile(this);
             x = (String) mVh.getVolatile(this);
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 368ae69..939100c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetVolatileStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getVolatile();
             x = (int) mVh.getVolatile();
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 3387a8d..728b199 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -13,16 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetVolatileStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -54,7 +53,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getVolatile();
             x = (String) mVh.getVolatile();
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 781e04f..bf5ef99 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddAcquireFieldLittleEndianFloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final float FIELD_VALUE = 3.14f;
     float mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         float x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (float) mVh.getAndAddAcquire(this, 2.17f);
             x = (float) mVh.getAndAddAcquire(this, 2.17f);
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 97f29ba..d15705e 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndAddAcquire(this, ~42);
             x = (int) mVh.getAndAddAcquire(this, ~42);
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 e108f7f..222a60d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddAcquireStaticFieldLittleEndianFloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final float FIELD_VALUE = 3.14f;
     static float sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         float x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (float) mVh.getAndAddAcquire(2.17f);
             x = (float) mVh.getAndAddAcquire(2.17f);
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 d0ae322..7436476 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndAddAcquire(~42);
             x = (int) mVh.getAndAddAcquire(~42);
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 1b80c40..cca97f4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddFieldLittleEndianFloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final float FIELD_VALUE = 3.14f;
     float mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         float x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (float) mVh.getAndAdd(this, 2.17f);
             x = (float) mVh.getAndAdd(this, 2.17f);
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 edacf181..170ee73 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndAdd(this, ~42);
             x = (int) mVh.getAndAdd(this, ~42);
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 0e86b0d..184f796 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddReleaseFieldLittleEndianFloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final float FIELD_VALUE = 3.14f;
     float mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         float x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (float) mVh.getAndAddRelease(this, 2.17f);
             x = (float) mVh.getAndAddRelease(this, 2.17f);
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 83446ff..7e75c44 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndAddRelease(this, ~42);
             x = (int) mVh.getAndAddRelease(this, ~42);
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 c1f1e6f..39c386b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddReleaseStaticFieldLittleEndianFloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final float FIELD_VALUE = 3.14f;
     static float sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         float x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (float) mVh.getAndAddRelease(2.17f);
             x = (float) mVh.getAndAddRelease(2.17f);
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 1b154a1..04ab531 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndAddRelease(~42);
             x = (int) mVh.getAndAddRelease(~42);
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 7de128d..b71351f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddStaticFieldLittleEndianFloatPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final float FIELD_VALUE = 3.14f;
     static float sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         float x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (float) mVh.getAndAdd(2.17f);
             x = (float) mVh.getAndAdd(2.17f);
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 c9a0926..e3955c0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandaddStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandaddStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndAdd(~42);
             x = (int) mVh.getAndAdd(~42);
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 fd9d9b1..adf05a6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseAndAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseAndAcquire(this, ~42);
             x = (int) mVh.getAndBitwiseAndAcquire(this, ~42);
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 c3c367f..4d657d9 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseAndAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseAndAcquire(~42);
             x = (int) mVh.getAndBitwiseAndAcquire(~42);
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 e073d28..dc64174 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseAndFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseAnd(this, ~42);
             x = (int) mVh.getAndBitwiseAnd(this, ~42);
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 ca78f5a..25d5631 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseAndReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseAndRelease(this, ~42);
             x = (int) mVh.getAndBitwiseAndRelease(this, ~42);
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 599f186..de2d548 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseAndReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseAndRelease(~42);
             x = (int) mVh.getAndBitwiseAndRelease(~42);
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 71fc0ae..36544c6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseAndStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseAnd(~42);
             x = (int) mVh.getAndBitwiseAnd(~42);
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 8fc4eab..fb36d0c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseOrAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseOrAcquire(this, ~42);
             x = (int) mVh.getAndBitwiseOrAcquire(this, ~42);
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 3368953..4194b12 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseOrAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseOrAcquire(~42);
             x = (int) mVh.getAndBitwiseOrAcquire(~42);
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 583a3a0..355c6e8 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseOrFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseOr(this, ~42);
             x = (int) mVh.getAndBitwiseOr(this, ~42);
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 1592fa6..401079d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseOrReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseOrRelease(this, ~42);
             x = (int) mVh.getAndBitwiseOrRelease(this, ~42);
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 d496083..322dcbf 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseOrReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseOrRelease(~42);
             x = (int) mVh.getAndBitwiseOrRelease(~42);
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 87276a5..c982814 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseOrStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseOr(~42);
             x = (int) mVh.getAndBitwiseOr(~42);
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 f7a372f..0b1cb32 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseXorAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseXorAcquire(this, ~42);
             x = (int) mVh.getAndBitwiseXorAcquire(this, ~42);
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 22726fc..4737072 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseXorAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseXorAcquire(~42);
             x = (int) mVh.getAndBitwiseXorAcquire(~42);
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 d071d6e..204cd70 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseXorFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseXor(this, ~42);
             x = (int) mVh.getAndBitwiseXor(this, ~42);
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 be2aa9c..b3ffed7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseXorReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseXorRelease(this, ~42);
             x = (int) mVh.getAndBitwiseXorRelease(this, ~42);
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 b0a7dcf..d0ab8de 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseXorReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseXorRelease(~42);
             x = (int) mVh.getAndBitwiseXorRelease(~42);
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 c5f99de..b378b68 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandbitwiseXorStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndBitwiseXor(~42);
             x = (int) mVh.getAndBitwiseXor(~42);
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 572e0c8..c7c66fe 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndSetAcquire(this, ~42);
             x = (int) mVh.getAndSetAcquire(this, ~42);
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 09be6d9..98d6bd7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetAcquireFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAndSetAcquire(this, null);
             x = (String) mVh.getAndSetAcquire(this, null);
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 4e0554a..206358f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndSetAcquire(~42);
             x = (int) mVh.getAndSetAcquire(~42);
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 5491522..0532e73 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetAcquireStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAndSetAcquire(null);
             x = (String) mVh.getAndSetAcquire(null);
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 a9303c6..f192d71 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndSet(this, ~42);
             x = (int) mVh.getAndSet(this, ~42);
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 bd4703f..0a8909c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAndSet(this, null);
             x = (String) mVh.getAndSet(this, null);
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 d9aee00..bfcb0f4 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndSetRelease(this, ~42);
             x = (int) mVh.getAndSetRelease(this, ~42);
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 2c79ca2..c6b0509 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetReleaseFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAndSetRelease(this, null);
             x = (String) mVh.getAndSetRelease(this, null);
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 ceff8163..45a01ed 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndSetRelease(~42);
             x = (int) mVh.getAndSetRelease(~42);
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 9b83504..3047281 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetReleaseStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAndSetRelease(null);
             x = (String) mVh.getAndSetRelease(null);
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 638da6f..6f1f1a0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (int) mVh.getAndSet(~42);
             x = (int) mVh.getAndSet(~42);
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 25d41141..c4d279f 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleGetandsetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleGetandsetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             x = (String) mVh.getAndSet(null);
             x = (String) mVh.getAndSet(null);
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 64ea9f3..c4f6005 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,9 +33,9 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetArrayLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int ELEMENT_VALUE = 42;
-    int[] mArray = { ELEMENT_VALUE };
+    int[] mArray = {ELEMENT_VALUE};
     VarHandle mVh;
 
     public VarHandleSetArrayLittleEndianIntPerfTest() throws Throwable {
@@ -54,7 +53,7 @@
     public void run() {
         int[] a = mArray;
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(a, 0, ~42);
             mVh.set(a, 0, ~42);
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 989d682..a6858c2 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetArrayLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,9 +33,9 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetArrayLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String ELEMENT_VALUE = "qwerty";
-    String[] mArray = { ELEMENT_VALUE };
+    String[] mArray = {ELEMENT_VALUE};
     VarHandle mVh;
 
     public VarHandleSetArrayLittleEndianStringPerfTest() throws Throwable {
@@ -54,7 +53,7 @@
     public void run() {
         String[] a = mArray;
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(a, 0, null);
             mVh.set(a, 0, null);
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 9d6d6b8..a994cbe 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewBigEndianIntPerfTest.java
@@ -13,52 +13,59 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetByteArrayViewBigEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int VALUE = 42;
-    byte[] mArray1 = { (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE };
-    byte[] mArray2 = { (byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE };
+    byte[] mArray1 = {
+        (byte) (VALUE >> 24), (byte) (VALUE >> 16), (byte) (VALUE >> 8), (byte) VALUE
+    };
+    byte[] mArray2 = {(byte) (-1 >> 24), (byte) (-1 >> 16), (byte) (-1 >> 8), (byte) VALUE};
     VarHandle mVh;
 
     public VarHandleSetByteArrayViewBigEndianIntPerfTest() throws Throwable {
         mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
-  }
+    }
 
     @After
     public void teardown() {
         if (!Arrays.equals(mArray2, mArray1)) {
-            throw new RuntimeException("array has unexpected values: " +
-                mArray2[0] + " " + mArray2[1] + " " + mArray2[2] + " " + mArray2[3]);
+            throw new RuntimeException(
+                    "array has unexpected values: "
+                            + mArray2[0]
+                            + " "
+                            + mArray2[1]
+                            + " "
+                            + mArray2[2]
+                            + " "
+                            + mArray2[3]);
         }
     }
 
     @Test
     public void run() {
         byte[] a = mArray2;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(a, 0, VALUE);
             mVh.set(a, 0, VALUE);
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 e8c3fa3..65412ec 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetByteArrayViewLittleEndianIntPerfTest.java
@@ -13,52 +13,59 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
-
-import java.util.Arrays;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetByteArrayViewLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int VALUE = 42;
-    byte[] mArray1 = { (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24) };
-    byte[] mArray2 = { (byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24) };
+    byte[] mArray1 = {
+        (byte) VALUE, (byte) (VALUE >> 8), (byte) (VALUE >> 16), (byte) (VALUE >> 24)
+    };
+    byte[] mArray2 = {(byte) VALUE, (byte) (-1 >> 8), (byte) (-1 >> 16), (byte) (-1 >> 24)};
     VarHandle mVh;
 
     public VarHandleSetByteArrayViewLittleEndianIntPerfTest() throws Throwable {
         mVh = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
-  }
+    }
 
     @After
     public void teardown() {
         if (!Arrays.equals(mArray2, mArray1)) {
-            throw new RuntimeException("array has unexpected values: " +
-                mArray2[0] + " " + mArray2[1] + " " + mArray2[2] + " " + mArray2[3]);
+            throw new RuntimeException(
+                    "array has unexpected values: "
+                            + mArray2[0]
+                            + " "
+                            + mArray2[1]
+                            + " "
+                            + mArray2[2]
+                            + " "
+                            + mArray2[3]);
         }
     }
 
     @Test
     public void run() {
         byte[] a = mArray2;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(a, 0, VALUE);
             mVh.set(a, 0, VALUE);
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 08294c0..573b0ff 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(this, FIELD_VALUE);
             mVh.set(this, FIELD_VALUE);
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 1e8a5bf..fe3c0fc 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(this, FIELD_VALUE);
             mVh.set(this, FIELD_VALUE);
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 2e5fb18..f398899 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetOpaqueFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setOpaque(this, FIELD_VALUE);
             mVh.setOpaque(this, FIELD_VALUE);
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 86a771f..7493120 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetOpaqueFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setOpaque(this, FIELD_VALUE);
             mVh.setOpaque(this, FIELD_VALUE);
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 903b310..5e73269 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetOpaqueStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setOpaque(FIELD_VALUE);
             mVh.setOpaque(FIELD_VALUE);
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 63cf7d2..9a217d1 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetOpaqueStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setOpaque(FIELD_VALUE);
             mVh.setOpaque(FIELD_VALUE);
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 d1a358d..1ce2270 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setRelease(this, FIELD_VALUE);
             mVh.setRelease(this, FIELD_VALUE);
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 b658324..ed84528 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetReleaseFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setRelease(this, FIELD_VALUE);
             mVh.setRelease(this, FIELD_VALUE);
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 47cb779..aeb9640 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setRelease(FIELD_VALUE);
             mVh.setRelease(FIELD_VALUE);
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 e48374e..8959a0c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetReleaseStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setRelease(FIELD_VALUE);
             mVh.setRelease(FIELD_VALUE);
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 0470d67..4007722 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(FIELD_VALUE);
             mVh.set(FIELD_VALUE);
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 00abb0b..7323158 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.set(FIELD_VALUE);
             mVh.set(FIELD_VALUE);
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 c66b23b..f4119c2 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetVolatileFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setVolatile(this, FIELD_VALUE);
             mVh.setVolatile(this, FIELD_VALUE);
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 1b36450..9b9c261 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetVolatileFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setVolatile(this, FIELD_VALUE);
             mVh.setVolatile(this, FIELD_VALUE);
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 75f9274..f125384 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetVolatileStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         int x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setVolatile(FIELD_VALUE);
             mVh.setVolatile(FIELD_VALUE);
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 8289d4f..2ad605d 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +33,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleSetVolatileStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -53,7 +52,7 @@
     @Test
     public void run() {
         String x;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mVh.setVolatile(FIELD_VALUE);
             mVh.setVolatile(FIELD_VALUE);
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 9fac842..5ef3bf0 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetAcquireFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetAcquire(this, mField, ~42);
             success = mVh.weakCompareAndSetAcquire(this, mField, 42);
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 2f60127..0c4ed66 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetAcquireFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetAcquire(this, mField, null);
             success = mVh.weakCompareAndSetAcquire(this, mField, "qwerty");
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 4efbd3e..db6bd24 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetAcquire(sField, ~42);
             success = mVh.weakCompareAndSetAcquire(sField, 42);
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 099640c..d2b0bf7 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
 
-    public VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest() throws Throwable {
+    public VarHandleWeakcompareandsetAcquireStaticFieldLittleEndianStringPerfTest()
+            throws Throwable {
         mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
     }
 
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetAcquire(sField, null);
             success = mVh.weakCompareAndSetAcquire(sField, "qwerty");
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 ce8f0f0..3cd5ae6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSet(this, mField, ~42);
             success = mVh.weakCompareAndSet(this, mField, 42);
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 c4119dc..6ddfc25 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSet(this, mField, null);
             success = mVh.weakCompareAndSet(this, mField, "qwerty");
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 abd981c..375f0bc 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetPlainFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetPlain(this, mField, ~42);
             success = mVh.weakCompareAndSetPlain(this, mField, 42);
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 c71e65f..7e2492a 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetPlainFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetPlain(this, mField, null);
             success = mVh.weakCompareAndSetPlain(this, mField, "qwerty");
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 f3c8f3a..190118c 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetPlain(sField, ~42);
             success = mVh.weakCompareAndSetPlain(sField, 42);
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 5c943a4..484ba1b 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetPlainStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetPlain(sField, null);
             success = mVh.weakCompareAndSetPlain(sField, "qwerty");
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 1755a15..80e4e15 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetReleaseFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     int mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetRelease(this, mField, ~42);
             success = mVh.weakCompareAndSetRelease(this, mField, 42);
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 77175b0..fa26c59 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetReleaseFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     String mField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetRelease(this, mField, null);
             success = mVh.weakCompareAndSetRelease(this, mField, "qwerty");
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 985519e..16bf2a20 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetRelease(sField, ~42);
             success = mVh.weakCompareAndSetRelease(sField, 42);
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 69e6ca7..e1716de 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,19 +32,20 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
 
-    public VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest() throws Throwable {
+    public VarHandleWeakcompareandsetReleaseStaticFieldLittleEndianStringPerfTest()
+            throws Throwable {
         mVh = MethodHandles.lookup().findStaticVarHandle(this.getClass(), "sField", String.class);
     }
 
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSetRelease(sField, null);
             success = mVh.weakCompareAndSetRelease(sField, "qwerty");
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 88df5ff..dc6f2ad 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetStaticFieldLittleEndianIntPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final int FIELD_VALUE = 42;
     static int sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSet(sField, ~42);
             success = mVh.weakCompareAndSet(sField, 42);
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 c296f668..d1096c6 100644
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest.java
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- // This file is generated by generate_java.py do not directly modify!
+// This file is generated by generate_java.py do not directly modify!
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -34,7 +32,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VarHandleWeakcompareandsetStaticFieldLittleEndianStringPerfTest {
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final String FIELD_VALUE = "qwerty";
     static String sField = FIELD_VALUE;
     VarHandle mVh;
@@ -46,7 +44,7 @@
     @Test
     public void run() {
         boolean success;
-        final BenchmarkState state = mBenchmarkRule.getState();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             success = mVh.weakCompareAndSet(sField, null);
             success = mVh.weakCompareAndSet(sField, "qwerty");
diff --git a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
index a43569a..4b4bc60 100755
--- a/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
+++ b/apct-tests/perftests/core/src/android/libcore/varhandles/generate_java.py
@@ -42,7 +42,7 @@
     return ''.join(c for c in word.title() if not c == '_')
 
 
-LOOP ="final BenchmarkState state = mBenchmarkRule.getState();\n        while (state.keepRunning())"
+LOOP ="BenchmarkState state = mPerfStatusReporter.getBenchmarkState();\n        while (state.keepRunning())"
 
 class Benchmark:
     def __init__(self, code, static, vartype, flavour, klass, method, memloc,
@@ -158,10 +158,10 @@
 VH_IMPORTS = """
 package android.libcore.varhandles;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
+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;
@@ -179,7 +179,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class {name} {{
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final {vartype} FIELD_VALUE = {value1};
     {static_kwd}{vartype} {static_prefix}Field = FIELD_VALUE;
     VarHandle mVh;
@@ -273,7 +273,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class {name} {{
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final {vartype} ELEMENT_VALUE = {value1};
     {vartype}[] mArray = {{ ELEMENT_VALUE }};
     VarHandle mVh;
@@ -324,7 +324,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class {name} {{
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     static final {vartype} VALUE = {value1};
     byte[] mArray1 = {value1_byte_array};
     byte[] mArray2 = {value2_byte_array};
@@ -375,7 +375,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class {name} {{
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     Field mField;
     {static_kwd}{vartype} {static_prefix}Value;
 
@@ -407,7 +407,7 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class {name} {{
-    @Rule public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     long mOffset;
     public {static_kwd}{vartype} {static_prefix}Value = {value1};
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index 16c2fd4..a0bf78f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -25,10 +25,7 @@
             ]
         },
         {
-            "name": "FrameworksServicesTests",
-            "options": [
-                {"include-filter": "com.android.server.job"}
-            ]
+            "name": "FrameworksServicesTests_com_android_server_job"
         },
         {
             "name": "CtsHostsideNetworkPolicyTests",
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index dd0d1b6..f56c14d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -21,10 +21,7 @@
       "name": "CtsUsageStatsTestCases"
     },
     {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {"include-filter": "com.android.server.usage"}
-      ]
+      "name": "FrameworksServicesTests_com_android_server_usage"
     }
   ]
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 5cdc57a..dada20e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -50805,6 +50805,7 @@
     method public android.view.Display.HdrCapabilities getHdrCapabilities();
     method public float getHdrSdrRatio();
     method @Deprecated public int getHeight();
+    method @FlaggedApi("com.android.server.display.feature.flags.highest_hdr_sdr_ratio_api") public float getHighestHdrSdrRatio();
     method @Deprecated public void getMetrics(android.util.DisplayMetrics);
     method public android.view.Display.Mode getMode();
     method public String getName();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index df707d1..1e94c2f 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -673,8 +673,8 @@
     method @Nullable public android.content.pm.PackageInfo getCurrentWebViewPackage();
     method @Nullable public String getCurrentWebViewPackageName();
     method @FlaggedApi("android.webkit.update_service_v2") @NonNull public android.webkit.WebViewProviderInfo getDefaultWebViewPackage();
-    method @Nullable public static android.webkit.WebViewUpdateManager getInstance();
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.QUERY_ALL_PACKAGES}) public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+    method @NonNull public static android.webkit.WebViewUpdateManager getInstance();
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
     method @NonNull public android.webkit.WebViewProviderResponse waitForAndGetProvider();
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fb425a9..475b1e2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -18769,7 +18769,7 @@
   public final class WebViewUpdateService {
     method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
     method public static String getCurrentWebViewPackageName();
-    method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
   }
 
 }
diff --git a/core/java/android/app/CameraCompatTaskInfo.java b/core/java/android/app/CameraCompatTaskInfo.java
index 53eddbe..432a0da 100644
--- a/core/java/android/app/CameraCompatTaskInfo.java
+++ b/core/java/android/app/CameraCompatTaskInfo.java
@@ -36,20 +36,36 @@
     public static final int CAMERA_COMPAT_FREEFORM_NONE = 0;
 
     /**
-     * The value to use when portrait camera compat treatment should be applied to a windowed task.
+     * The value to use when camera compat treatment should be applied to an activity requesting
+     * portrait orientation, while a device is in landscape. Applies only to freeform tasks.
      */
-    public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT = 1;
+    public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE = 1;
 
     /**
-     * The value to use when landscape camera compat treatment should be applied to a windowed task.
+     * The value to use when camera compat treatment should be applied to an activity requesting
+     * landscape orientation, while a device is in landscape. Applies only to freeform tasks.
      */
-    public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE = 2;
+    public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE = 2;
+
+    /**
+     * The value to use when camera compat treatment should be applied to an activity requesting
+     * portrait orientation, while a device is in portrait. Applies only to freeform tasks.
+     */
+    public static final int CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT = 3;
+
+    /**
+     * The value to use when camera compat treatment should be applied to an activity requesting
+     * landscape orientation, while a device is in portrait. Applies only to freeform tasks.
+     */
+    public static final int CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT = 4;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "CAMERA_COMPAT_FREEFORM_" }, value = {
             CAMERA_COMPAT_FREEFORM_NONE,
-            CAMERA_COMPAT_FREEFORM_PORTRAIT,
-            CAMERA_COMPAT_FREEFORM_LANDSCAPE,
+            CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE,
+            CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE,
+            CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT,
+            CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT,
     })
     public @interface FreeformCameraCompatMode {}
 
@@ -143,8 +159,14 @@
             @FreeformCameraCompatMode int freeformCameraCompatMode) {
         return switch (freeformCameraCompatMode) {
             case CAMERA_COMPAT_FREEFORM_NONE -> "inactive";
-            case CAMERA_COMPAT_FREEFORM_PORTRAIT -> "portrait";
-            case CAMERA_COMPAT_FREEFORM_LANDSCAPE -> "landscape";
+            case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE ->
+                    "app-portrait-device-landscape";
+            case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE ->
+                    "app-landscape-device-landscape";
+            case CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT ->
+                    "app-portrait-device-portrait";
+            case CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT ->
+                    "app-landscape-device-portrait";
             default -> throw new AssertionError(
                     "Unexpected camera compat mode: " + freeformCameraCompatMode);
         };
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 32e9542..4a2b016 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -55,7 +55,9 @@
 import java.io.PrintWriter;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -100,6 +102,11 @@
     @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
     public static final String RECS_ID = "android.app.recs";
 
+    /** @hide */
+    @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION)
+    public static final ArrayList<String> SYSTEM_RESERVED_IDS = new ArrayList<>(
+            List.of(NEWS_ID, SOCIAL_MEDIA_ID, PROMOTIONS_ID, RECS_ID));
+
     /**
      * The formatter used by the system to create an id for notification
      * channels when it automatically creates conversation channels on behalf of an app. The format
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e44e776..5147f12 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -104,6 +104,7 @@
 import android.devicelock.DeviceLockFrameworkInitializer;
 import android.graphics.fonts.FontManager;
 import android.hardware.ConsumerIrManager;
+import android.hardware.ISensorPrivacyManager;
 import android.hardware.ISerialManager;
 import android.hardware.SensorManager;
 import android.hardware.SensorPrivacyManager;
@@ -707,8 +708,12 @@
         registerService(Context.SENSOR_PRIVACY_SERVICE, SensorPrivacyManager.class,
                 new CachedServiceFetcher<SensorPrivacyManager>() {
                     @Override
-                    public SensorPrivacyManager createService(ContextImpl ctx) {
-                        return SensorPrivacyManager.getInstance(ctx);
+                    public SensorPrivacyManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.SENSOR_PRIVACY_SERVICE);
+                        return SensorPrivacyManager.getInstance(
+                                ctx, ISensorPrivacyManager.Stub.asInterface(b));
                     }});
 
         registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index c7b0be7..46567c4 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -1107,7 +1107,7 @@
     /**
      * Called to notify the state of operations that can be unsafe to execute has changed.
      *
-     * <p><b>Note:/b> notice that the operation safety state might change between the time this
+     * <p><b>Note:</b> notice that the operation safety state might change between the time this
      * callback is received and the operation's method on {@link DevicePolicyManager} is called, so
      * calls to the latter could still throw a {@link UnsafeStateException} even when this method
      * is called with {@code isSafe} as {@code true}
diff --git a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
index 085e0a4..a23f842 100644
--- a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
+++ b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
@@ -37,6 +37,8 @@
 public class AppFunctionStaticMetadataHelper {
     public static final String STATIC_SCHEMA_TYPE = "AppFunctionStaticMetadata";
     public static final String STATIC_PROPERTY_ENABLED_BY_DEFAULT = "enabledByDefault";
+    public static final String STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS =
+        "restrictCallersWithExecuteAppFunctions";
 
     public static final String APP_FUNCTION_STATIC_NAMESPACE = "app_functions";
     public static final String PROPERTY_FUNCTION_ID = "functionId";
diff --git a/core/java/android/app/jank/flags.aconfig b/core/java/android/app/jank/flags.aconfig
new file mode 100644
index 0000000..5657f7e
--- /dev/null
+++ b/core/java/android/app/jank/flags.aconfig
@@ -0,0 +1,16 @@
+package: "android.app.jank"
+container: "system"
+
+flag {
+  name: "detailed_app_jank_metrics_api"
+  namespace: "system_performance"
+  description: "Control the API portion of Detailed Application Jank Metrics"
+  bug: "366264614"
+}
+
+flag {
+  name: "detailed_app_jank_metrics_logging_enabled"
+  namespace: "system_performance"
+  description: "Controls whether the system will log frame metrics related to app jank"
+  bug: "366265225"
+}
\ No newline at end of file
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 60d1b0d..e895d7b 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -3141,14 +3141,6 @@
             for (int i = 0; i < N; i++) {
                 mUriRelativeFilterGroups.add(new UriRelativeFilterGroup(source));
             }
-            if (source.dataAvail() > 0) {
-                Log.e(TAG, "Parcel data not fully consumed after completed reading"
-                        + " UriRelativeFilterGroup data");
-            }
-        }
-        if (source.dataAvail() > 0) {
-            Log.e(TAG, "Parcel data not fully consumed when unparceling intent filter",
-                    new Exception());
         }
     }
 
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 7c2edd7..139ff65 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -285,4 +285,12 @@
     namespace: "package_manager_service"
     description: "Feature flag to enable the feature to retrieve package info without installation with a file descriptor."
     bug: "340879905"
+}
+
+flag {
+    name: "get_packages_from_launcher_apps"
+    namespace: "package_manager_service"
+    description: "Feature flag to provide the new methods within launcher apps class to get packages."
+    bug: "363324203"
+    is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 4cdaaddd..a4c0e87 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -797,7 +797,7 @@
     public void setSensorPrivacy(@Sensors.Sensor int sensor,
             boolean enable) {
         setSensorPrivacy(resolveSourceFromCurrentContext(), sensor, enable,
-                UserHandle.USER_CURRENT);
+                mContext.getUserId());
     }
 
     private @Sources.Source int resolveSourceFromCurrentContext() {
@@ -837,6 +837,8 @@
     @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
     public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
             boolean enable) {
+        // TODO(b/348510106): Replace USER_CURRENT with Context user and fix any tests that may be
+        // affected.
         setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT);
     }
 
@@ -894,7 +896,7 @@
     @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
     public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
             @Sensors.Sensor int sensor, boolean enable) {
-        setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT);
+        setSensorPrivacyForProfileGroup(source , sensor, enable, mContext.getUserId());
     }
 
     /**
@@ -950,7 +952,7 @@
     @RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
     public void suppressSensorPrivacyReminders(int sensor,
             boolean suppress) {
-        suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT);
+        suppressSensorPrivacyReminders(sensor, suppress, mContext.getUserId());
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 6a7ee7f..d40b2e3 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -29,6 +29,7 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.app.ActivityManager;
+import android.app.CameraCompatTaskInfo;
 import android.app.TaskInfo;
 import android.app.compat.CompatChanges;
 import android.companion.virtual.VirtualDeviceManager;
@@ -1586,12 +1587,13 @@
                     context.getSystemService(ActivityManager.class);
             for (ActivityManager.AppTask appTask : activityManager.getAppTasks()) {
                 final TaskInfo taskInfo = appTask.getTaskInfo();
-                if (taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode
-                        != 0
+                final int freeformCameraCompatMode =
+                        taskInfo.appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode;
+                if (freeformCameraCompatMode != 0
                         && taskInfo.topActivity != null
                         && taskInfo.topActivity.getPackageName().equals(packageName)) {
                     // WindowManager has requested rotation override.
-                    return ICameraService.ROTATION_OVERRIDE_ROTATION_ONLY;
+                    return getRotationOverrideForCompatFreeform(freeformCameraCompatMode);
                 }
             }
         }
@@ -1613,6 +1615,19 @@
                 : ICameraService.ROTATION_OVERRIDE_NONE;
     }
 
+    private static int getRotationOverrideForCompatFreeform(
+            @CameraCompatTaskInfo.FreeformCameraCompatMode int freeformCameraCompatMode) {
+        // Only rotate-and-crop if the app and device orientations do not match.
+        if (freeformCameraCompatMode
+                == CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT
+                || freeformCameraCompatMode
+                    == CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE) {
+            return ICameraService.ROTATION_OVERRIDE_ROTATION_ONLY;
+        } else {
+            return ICameraService.ROTATION_OVERRIDE_NONE;
+        }
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 85e33a8..9612a53 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -21,6 +21,7 @@
 import static android.view.Display.HdrCapabilities.HdrType;
 
 import android.Manifest;
+import android.annotation.FlaggedApi;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -1232,6 +1233,20 @@
     }
 
     /**
+     * @param displayId The ID of the display
+     * @return The highest HDR/SDR ratio of the ratios defined in Display Device Config. If no
+     * HDR/SDR map is defined, this always returns 1.
+     */
+    @FlaggedApi(com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API)
+    public float getHighestHdrSdrRatio(int displayId) {
+        try {
+            return mDm.getHighestHdrSdrRatio(displayId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @see DisplayManager#getDozeBrightnessSensorValueToBrightness
      */
     @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index f3c21e9f..aa1539f6 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -247,6 +247,9 @@
     @EnforcePermission("RESTRICT_DISPLAY_MODES")
     void requestDisplayModes(in IBinder token, int displayId, in @nullable int[] modeIds);
 
+    // Get the highest defined HDR/SDR ratio for a display.
+    float getHighestHdrSdrRatio(int displayId);
+
     // Get the mapping between the doze brightness sensor values and brightness values
     @EnforcePermission("CONTROL_DISPLAY_BRIGHTNESS")
     float[] getDozeBrightnessSensorValueToBrightness(int displayId);
diff --git a/core/java/android/hardware/input/AidlKeyGestureEvent.aidl b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl
new file mode 100644
index 0000000..7cf8795
--- /dev/null
+++ b/core/java/android/hardware/input/AidlKeyGestureEvent.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/** @hide */
+@JavaDerive(equals=true)
+parcelable AidlKeyGestureEvent {
+    int deviceId;
+    int[] keycodes;
+    int modifierState;
+    int gestureType;
+    int action;
+    int displayId;
+    int flags;
+}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 2d96bba..102f56e 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -26,6 +26,7 @@
 import android.hardware.input.IKeyboardBacklightListener;
 import android.hardware.input.IKeyboardBacklightState;
 import android.hardware.input.IKeyGestureEventListener;
+import android.hardware.input.IKeyGestureHandler;
 import android.hardware.input.IStickyModifierStateListener;
 import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.KeyboardLayoutSelectionResult;
@@ -250,4 +251,14 @@
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
             + "android.Manifest.permission.MANAGE_KEY_GESTURES)")
     void unregisterKeyGestureEventListener(IKeyGestureEventListener listener);
+
+    @PermissionManuallyEnforced
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.MANAGE_KEY_GESTURES)")
+    void registerKeyGestureHandler(IKeyGestureHandler handler);
+
+    @PermissionManuallyEnforced
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.MANAGE_KEY_GESTURES)")
+    void unregisterKeyGestureHandler(IKeyGestureHandler handler);
 }
diff --git a/core/java/android/hardware/input/IKeyGestureEventListener.aidl b/core/java/android/hardware/input/IKeyGestureEventListener.aidl
index 2c430f1..6b5f837 100644
--- a/core/java/android/hardware/input/IKeyGestureEventListener.aidl
+++ b/core/java/android/hardware/input/IKeyGestureEventListener.aidl
@@ -16,11 +16,13 @@
 
 package android.hardware.input;
 
+import android.hardware.input.AidlKeyGestureEvent;
+
 /** @hide */
 oneway interface IKeyGestureEventListener {
 
     /**
      * Called when a key gesture event occurs.
      */
-    void onKeyGestureEvent(int deviceId, in int[] keycodes, int modifierState, int shortcut);
+    void onKeyGestureEvent(in AidlKeyGestureEvent event);
 }
diff --git a/core/java/android/hardware/input/IKeyGestureHandler.aidl b/core/java/android/hardware/input/IKeyGestureHandler.aidl
new file mode 100644
index 0000000..509b948
--- /dev/null
+++ b/core/java/android/hardware/input/IKeyGestureHandler.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.hardware.input.AidlKeyGestureEvent;
+import android.os.IBinder;
+
+/** @hide */
+interface IKeyGestureHandler {
+
+    /**
+     * Called when a key gesture starts, ends, or is cancelled. If a handler returns {@code true},
+     * it means they intend to handle the full gesture and should handle all the events pertaining
+     * to that gesture.
+     */
+    boolean handleKeyGesture(in AidlKeyGestureEvent event, in IBinder focusedToken);
+
+    /**
+     * Called to know if a particular gesture type is supported by the handler.
+     *
+     * TODO(b/358569822): Remove this call to reduce the binder calls to single call for
+     *  handleKeyGesture. For this we need to remove dependency of multi-key gestures to identify if
+     *  a key gesture is supported on first relevant key down.
+     *  Also, for now we prioritize handlers in the system server process above external handlers to
+     *  reduce IPC binder calls.
+     */
+    boolean isKeyGestureSupported(int gestureType);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 04cfcd8..22728f7 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1406,6 +1406,33 @@
     }
 
     /**
+     * Registers a key gesture event handler for {@link KeyGestureEvent} handling.
+     *
+     * @param handler the {@link KeyGestureEventHandler}
+     * @throws IllegalArgumentException if {@code handler} has already been registered previously.
+     * @throws NullPointerException     if {@code handler} or {@code executor} is null.
+     * @hide
+     * @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler)
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+    public void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler)
+            throws IllegalArgumentException {
+        mGlobal.registerKeyGestureEventHandler(handler);
+    }
+
+    /**
+     * Unregisters a previously added key gesture event handler.
+     *
+     * @param handler the {@link KeyGestureEventHandler}
+     * @hide
+     * @see #registerKeyGestureEventHandler(KeyGestureEventHandler)
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+    public void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
+        mGlobal.unregisterKeyGestureEventHandler(handler);
+    }
+
+    /**
      * A callback used to be notified about battery state changes for an input device. The
      * {@link #onBatteryStateChanged(int, long, BatteryState)} method will be called once after the
      * listener is successfully registered to provide the initial battery state of the device.
@@ -1522,4 +1549,35 @@
          */
         void onKeyGestureEvent(@NonNull KeyGestureEvent event);
     }
+
+    /**
+     * A callback used to notify about key gesture event start, complete and cancel. Unlike
+     * {@see KeyGestureEventListener} which is to listen to successfully handled key gestures, this
+     * interface allows system components to register handler for handling key gestures.
+     *
+     * @see #registerKeyGestureEventHandler(KeyGestureEventHandler)
+     * @see #unregisterKeyGestureEventHandler(KeyGestureEventHandler)
+     *
+     * <p> NOTE: All callbacks will occur on system main and input threads, so the caller needs
+     * to move time-consuming operations to appropriate handler threads.
+     * @hide
+     */
+    public interface KeyGestureEventHandler {
+        /**
+         * Called when a key gesture event starts, is completed, or is cancelled. If a handler
+         * returns {@code true}, it implies that the handler intends to handle the key gesture and
+         * only this handler will receive the future events for this key gesture.
+         *
+         * @param event the gesture event
+         */
+        boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
+                @Nullable IBinder focusedToken);
+
+        /**
+         * Called to identify if a particular gesture is of interest to a handler.
+         *
+         * NOTE: If no active handler supports certain gestures, the gestures will not be captured.
+         */
+        boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType);
+    }
 }
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 2a36238..5c11346 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -25,6 +25,7 @@
 import android.hardware.SensorManager;
 import android.hardware.input.InputManager.InputDeviceBatteryListener;
 import android.hardware.input.InputManager.InputDeviceListener;
+import android.hardware.input.InputManager.KeyGestureEventHandler;
 import android.hardware.input.InputManager.KeyGestureEventListener;
 import android.hardware.input.InputManager.KeyboardBacklightListener;
 import android.hardware.input.InputManager.OnTabletModeChangedListener;
@@ -119,6 +120,14 @@
     @Nullable
     private IKeyGestureEventListener mKeyGestureEventListener;
 
+    private final Object mKeyGestureEventHandlerLock = new Object();
+    @GuardedBy("mKeyGestureEventHandlerLock")
+    @Nullable
+    private ArrayList<KeyGestureEventHandler> mKeyGestureEventHandlers;
+    @GuardedBy("mKeyGestureEventHandlerLock")
+    @Nullable
+    private IKeyGestureHandler mKeyGestureHandler;
+
     // InputDeviceSensorManager gets notified synchronously from the binder thread when input
     // devices change, so it must be synchronized with the input device listeners.
     @GuardedBy("mInputDeviceListeners")
@@ -1080,18 +1089,14 @@
     }
 
     private class LocalKeyGestureEventListener extends IKeyGestureEventListener.Stub {
-
         @Override
-        public void onKeyGestureEvent(int deviceId, int[] keycodes, int modifierState,
-                int gestureType) {
+        public void onKeyGestureEvent(@NonNull AidlKeyGestureEvent ev) {
             synchronized (mKeyGestureEventListenerLock) {
                 if (mKeyGestureEventListeners == null) return;
                 final int numListeners = mKeyGestureEventListeners.size();
+                final KeyGestureEvent event = new KeyGestureEvent(ev);
                 for (int i = 0; i < numListeners; i++) {
-                    mKeyGestureEventListeners.get(i)
-                            .onKeyGestureEvent(
-                                    new KeyGestureEvent(deviceId, keycodes, modifierState,
-                                            gestureType));
+                    mKeyGestureEventListeners.get(i).onKeyGestureEvent(event);
                 }
             }
         }
@@ -1154,6 +1159,96 @@
         }
     }
 
+    private class LocalKeyGestureHandler extends IKeyGestureHandler.Stub {
+        @Override
+        public boolean handleKeyGesture(@NonNull AidlKeyGestureEvent ev, IBinder focusedToken) {
+            synchronized (mKeyGestureEventHandlerLock) {
+                if (mKeyGestureEventHandlers == null) {
+                    return false;
+                }
+                final int numHandlers = mKeyGestureEventHandlers.size();
+                final KeyGestureEvent event = new KeyGestureEvent(ev);
+                for (int i = 0; i < numHandlers; i++) {
+                    KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i);
+                    if (handler.handleKeyGestureEvent(event, focusedToken)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
+            synchronized (mKeyGestureEventHandlerLock) {
+                if (mKeyGestureEventHandlers == null) {
+                    return false;
+                }
+                final int numHandlers = mKeyGestureEventHandlers.size();
+                for (int i = 0; i < numHandlers; i++) {
+                    KeyGestureEventHandler handler = mKeyGestureEventHandlers.get(i);
+                    if (handler.isKeyGestureSupported(gestureType)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * @see InputManager#registerKeyGestureEventHandler(KeyGestureEventHandler)
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+    void registerKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler)
+            throws IllegalArgumentException {
+        Objects.requireNonNull(handler, "handler should not be null");
+
+        synchronized (mKeyGestureEventHandlerLock) {
+            if (mKeyGestureHandler == null) {
+                mKeyGestureEventHandlers = new ArrayList<>();
+                mKeyGestureHandler = new LocalKeyGestureHandler();
+
+                try {
+                    mIm.registerKeyGestureHandler(mKeyGestureHandler);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+            final int numHandlers = mKeyGestureEventHandlers.size();
+            for (int i = 0; i < numHandlers; i++) {
+                if (mKeyGestureEventHandlers.get(i) == handler) {
+                    throw new IllegalArgumentException("Handler has already been registered!");
+                }
+            }
+            mKeyGestureEventHandlers.add(handler);
+        }
+    }
+
+    /**
+     * @see InputManager#unregisterKeyGestureEventHandler(KeyGestureEventHandler)
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+    void unregisterKeyGestureEventHandler(@NonNull KeyGestureEventHandler handler) {
+        Objects.requireNonNull(handler, "handler should not be null");
+
+        synchronized (mKeyGestureEventHandlerLock) {
+            if (mKeyGestureEventHandlers == null) {
+                return;
+            }
+            mKeyGestureEventHandlers.removeIf(existingHandler -> existingHandler == handler);
+            if (mKeyGestureEventHandlers.isEmpty()) {
+                try {
+                    mIm.unregisterKeyGestureHandler(mKeyGestureHandler);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+                mKeyGestureEventHandlers = null;
+                mKeyGestureHandler = null;
+            }
+        }
+    }
+
     /**
      * TODO(b/330517633): Cleanup the unsupported API
      */
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 7a8dd33..c7ebc63 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -19,8 +19,11 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.view.Display;
+import android.view.KeyCharacterMap;
 
-import com.android.internal.util.DataClass;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AnnotationValidations;
 import com.android.internal.util.FrameworkStatsLog;
 
 import java.lang.annotation.Retention;
@@ -31,501 +34,511 @@
  *
  * @hide
  */
-@DataClass(genToString = true, genEqualsHashCode = true)
-public class KeyGestureEvent {
+public final class KeyGestureEvent {
 
-    private final int mDeviceId;
     @NonNull
-    private final int[] mKeycodes;
-    private final int mModifierState;
-    @KeyGestureType
-    private final int mKeyGestureType;
+    private AidlKeyGestureEvent mKeyGestureEvent;
 
+    public static final int KEY_GESTURE_TYPE_UNSPECIFIED = 0;
+    public static final int KEY_GESTURE_TYPE_HOME = 1;
+    public static final int KEY_GESTURE_TYPE_RECENT_APPS = 2;
+    public static final int KEY_GESTURE_TYPE_BACK = 3;
+    public static final int KEY_GESTURE_TYPE_APP_SWITCH = 4;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT = 5;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT = 6;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS = 7;
+    public static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL = 8;
+    public static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR = 9;
+    public static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT = 10;
+    public static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER = 11;
+    public static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP = 12;
+    public static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN = 13;
+    public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP = 14;
+    public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN = 15;
+    public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE = 16;
+    public static final int KEY_GESTURE_TYPE_VOLUME_UP = 17;
+    public static final int KEY_GESTURE_TYPE_VOLUME_DOWN = 18;
+    public static final int KEY_GESTURE_TYPE_VOLUME_MUTE = 19;
+    public static final int KEY_GESTURE_TYPE_ALL_APPS = 20;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH = 21;
+    public static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH = 22;
+    public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS = 23;
+    public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK = 24;
+    public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE = 25;
+    public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION = 26;
+    public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS = 27;
+    public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT = 28;
+    public static final int KEY_GESTURE_TYPE_LOCK_SCREEN = 29;
+    public static final int KEY_GESTURE_TYPE_OPEN_NOTES = 30;
+    public static final int KEY_GESTURE_TYPE_TOGGLE_POWER = 31;
+    public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION = 32;
+    public static final int KEY_GESTURE_TYPE_SLEEP = 33;
+    public static final int KEY_GESTURE_TYPE_WAKEUP = 34;
+    public static final int KEY_GESTURE_TYPE_MEDIA_KEY = 35;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER = 36;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL = 37;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS = 38;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR = 39;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR = 40;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC = 41;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS = 42;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING = 43;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY = 44;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES = 45;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER = 46;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS = 47;
+    public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME = 48;
+    public static final int KEY_GESTURE_TYPE_DESKTOP_MODE = 49;
+    public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION = 50;
 
-    public static final int KEY_GESTURE_TYPE_UNSPECIFIED =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
-    public static final int KEY_GESTURE_TYPE_HOME =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME;
-    public static final int KEY_GESTURE_TYPE_RECENT_APPS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS;
-    public static final int KEY_GESTURE_TYPE_BACK =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK;
-    public static final int KEY_GESTURE_TYPE_APP_SWITCH =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS;
-    public static final int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL;
-    public static final int KEY_GESTURE_TYPE_TOGGLE_TASKBAR =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR;
-    public static final int KEY_GESTURE_TYPE_TAKE_SCREENSHOT =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT;
-    public static final int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER;
-    public static final int KEY_GESTURE_TYPE_BRIGHTNESS_UP =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP;
-    public static final int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN;
-    public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP;
-    public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN;
-    public static final int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE;
-    public static final int KEY_GESTURE_TYPE_VOLUME_UP =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP;
-    public static final int KEY_GESTURE_TYPE_VOLUME_DOWN =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN;
-    public static final int KEY_GESTURE_TYPE_VOLUME_MUTE =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE;
-    public static final int KEY_GESTURE_TYPE_ALL_APPS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_SEARCH =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH;
-    public static final int KEY_GESTURE_TYPE_LANGUAGE_SWITCH =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH;
-    public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS;
-    public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK;
-    public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE;
-    public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION;
-    public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS;
-    public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT;
-    public static final int KEY_GESTURE_TYPE_LOCK_SCREEN =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN;
-    public static final int KEY_GESTURE_TYPE_OPEN_NOTES =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES;
-    public static final int KEY_GESTURE_TYPE_TOGGLE_POWER =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER;
-    public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION;
-    public static final int KEY_GESTURE_TYPE_SLEEP =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP;
-    public static final int KEY_GESTURE_TYPE_WAKEUP =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP;
-    public static final int KEY_GESTURE_TYPE_MEDIA_KEY =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS;
-    public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME;
-    public static final int KEY_GESTURE_TYPE_DESKTOP_MODE =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
-    public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION =
-            FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
+    public static final int FLAG_CANCELLED = 1;
 
+    // NOTE: Valid KeyGestureEvent streams:
+    //       - GESTURE_START -> GESTURE_CANCEL
+    //       - GESTURE_START -> GESTURE_COMPLETE
+    //       - GESTURE_COMPLETE
 
-
-    // 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/KeyGestureEvent.java
-    //
-    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
-    //   Settings > Editor > Code Style > Formatter Control
-    //@formatter:off
-
+    /** Key gesture started (e.g. Key down of the relevant key) */
+    public static final int ACTION_GESTURE_START = 1;
+    /** Key gesture completed (e.g. Key up of the relevant key) */
+    public static final int ACTION_GESTURE_COMPLETE = 2;
 
     @IntDef(prefix = "KEY_GESTURE_TYPE_", value = {
-        KEY_GESTURE_TYPE_UNSPECIFIED,
-        KEY_GESTURE_TYPE_HOME,
-        KEY_GESTURE_TYPE_RECENT_APPS,
-        KEY_GESTURE_TYPE_BACK,
-        KEY_GESTURE_TYPE_APP_SWITCH,
-        KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
-        KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT,
-        KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
-        KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
-        KEY_GESTURE_TYPE_TOGGLE_TASKBAR,
-        KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
-        KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
-        KEY_GESTURE_TYPE_BRIGHTNESS_UP,
-        KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
-        KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
-        KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
-        KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
-        KEY_GESTURE_TYPE_VOLUME_UP,
-        KEY_GESTURE_TYPE_VOLUME_DOWN,
-        KEY_GESTURE_TYPE_VOLUME_MUTE,
-        KEY_GESTURE_TYPE_ALL_APPS,
-        KEY_GESTURE_TYPE_LAUNCH_SEARCH,
-        KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
-        KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
-        KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
-        KEY_GESTURE_TYPE_SYSTEM_MUTE,
-        KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
-        KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS,
-        KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
-        KEY_GESTURE_TYPE_LOCK_SCREEN,
-        KEY_GESTURE_TYPE_OPEN_NOTES,
-        KEY_GESTURE_TYPE_TOGGLE_POWER,
-        KEY_GESTURE_TYPE_SYSTEM_NAVIGATION,
-        KEY_GESTURE_TYPE_SLEEP,
-        KEY_GESTURE_TYPE_WAKEUP,
-        KEY_GESTURE_TYPE_MEDIA_KEY,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER,
-        KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS,
-        KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME,
-        KEY_GESTURE_TYPE_DESKTOP_MODE,
-        KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION
+            KEY_GESTURE_TYPE_UNSPECIFIED,
+            KEY_GESTURE_TYPE_HOME,
+            KEY_GESTURE_TYPE_RECENT_APPS,
+            KEY_GESTURE_TYPE_BACK,
+            KEY_GESTURE_TYPE_APP_SWITCH,
+            KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
+            KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT,
+            KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
+            KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+            KEY_GESTURE_TYPE_TOGGLE_TASKBAR,
+            KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+            KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
+            KEY_GESTURE_TYPE_BRIGHTNESS_UP,
+            KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
+            KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
+            KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
+            KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
+            KEY_GESTURE_TYPE_VOLUME_UP,
+            KEY_GESTURE_TYPE_VOLUME_DOWN,
+            KEY_GESTURE_TYPE_VOLUME_MUTE,
+            KEY_GESTURE_TYPE_ALL_APPS,
+            KEY_GESTURE_TYPE_LAUNCH_SEARCH,
+            KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+            KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+            KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+            KEY_GESTURE_TYPE_SYSTEM_MUTE,
+            KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
+            KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS,
+            KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
+            KEY_GESTURE_TYPE_LOCK_SCREEN,
+            KEY_GESTURE_TYPE_OPEN_NOTES,
+            KEY_GESTURE_TYPE_TOGGLE_POWER,
+            KEY_GESTURE_TYPE_SYSTEM_NAVIGATION,
+            KEY_GESTURE_TYPE_SLEEP,
+            KEY_GESTURE_TYPE_WAKEUP,
+            KEY_GESTURE_TYPE_MEDIA_KEY,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER,
+            KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS,
+            KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME,
+            KEY_GESTURE_TYPE_DESKTOP_MODE,
+            KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
     })
     @Retention(RetentionPolicy.SOURCE)
-    @DataClass.Generated.Member
-    public @interface KeyGestureType {}
+    public @interface KeyGestureType {
+    }
 
-    @DataClass.Generated.Member
-    public static String keyGestureTypeToString(@KeyGestureType int value) {
-        switch (value) {
-            case KEY_GESTURE_TYPE_UNSPECIFIED:
-                    return "KEY_GESTURE_TYPE_UNSPECIFIED";
-            case KEY_GESTURE_TYPE_HOME:
-                    return "KEY_GESTURE_TYPE_HOME";
-            case KEY_GESTURE_TYPE_RECENT_APPS:
-                    return "KEY_GESTURE_TYPE_RECENT_APPS";
-            case KEY_GESTURE_TYPE_BACK:
-                    return "KEY_GESTURE_TYPE_BACK";
-            case KEY_GESTURE_TYPE_APP_SWITCH:
-                    return "KEY_GESTURE_TYPE_APP_SWITCH";
-            case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
-                    return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT";
-            case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
-                    return "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT";
-            case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
-                    return "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS";
-            case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
-                    return "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL";
-            case KEY_GESTURE_TYPE_TOGGLE_TASKBAR:
-                    return "KEY_GESTURE_TYPE_TOGGLE_TASKBAR";
-            case KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
-                    return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT";
-            case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
-                    return "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER";
-            case KEY_GESTURE_TYPE_BRIGHTNESS_UP:
-                    return "KEY_GESTURE_TYPE_BRIGHTNESS_UP";
-            case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
-                    return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN";
-            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
-                    return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP";
-            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
-                    return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN";
-            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
-                    return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE";
-            case KEY_GESTURE_TYPE_VOLUME_UP:
-                    return "KEY_GESTURE_TYPE_VOLUME_UP";
-            case KEY_GESTURE_TYPE_VOLUME_DOWN:
-                    return "KEY_GESTURE_TYPE_VOLUME_DOWN";
-            case KEY_GESTURE_TYPE_VOLUME_MUTE:
-                    return "KEY_GESTURE_TYPE_VOLUME_MUTE";
-            case KEY_GESTURE_TYPE_ALL_APPS:
-                    return "KEY_GESTURE_TYPE_ALL_APPS";
-            case KEY_GESTURE_TYPE_LAUNCH_SEARCH:
-                    return "KEY_GESTURE_TYPE_LAUNCH_SEARCH";
-            case KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
-                    return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH";
-            case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
-                    return "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS";
-            case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
-                    return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK";
-            case KEY_GESTURE_TYPE_SYSTEM_MUTE:
-                    return "KEY_GESTURE_TYPE_SYSTEM_MUTE";
-            case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
-                    return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION";
-            case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
-                    return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS";
-            case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
-                    return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT";
-            case KEY_GESTURE_TYPE_LOCK_SCREEN:
-                    return "KEY_GESTURE_TYPE_LOCK_SCREEN";
-            case KEY_GESTURE_TYPE_OPEN_NOTES:
-                    return "KEY_GESTURE_TYPE_OPEN_NOTES";
-            case KEY_GESTURE_TYPE_TOGGLE_POWER:
-                    return "KEY_GESTURE_TYPE_TOGGLE_POWER";
-            case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION:
-                    return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION";
-            case KEY_GESTURE_TYPE_SLEEP:
-                    return "KEY_GESTURE_TYPE_SLEEP";
-            case KEY_GESTURE_TYPE_WAKEUP:
-                    return "KEY_GESTURE_TYPE_WAKEUP";
-            case KEY_GESTURE_TYPE_MEDIA_KEY:
-                    return "KEY_GESTURE_TYPE_MEDIA_KEY";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER";
-            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS:
-                    return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS";
-            case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME:
-                    return "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME";
-            case KEY_GESTURE_TYPE_DESKTOP_MODE:
-                    return "KEY_GESTURE_TYPE_DESKTOP_MODE";
-            case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
-                    return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION";
-            default: return Integer.toHexString(value);
+    public KeyGestureEvent(@NonNull AidlKeyGestureEvent keyGestureEvent) {
+        this.mKeyGestureEvent = keyGestureEvent;
+    }
+
+    /**
+     * Key gesture event builder used to create a KeyGestureEvent for tests in Java.
+     *
+     * @hide
+     */
+    public static class Builder {
+        private int mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
+        private int[] mKeycodes = new int[0];
+        private int mModifierState = 0;
+        @KeyGestureType
+        private int mKeyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_UNSPECIFIED;
+        private int mAction = KeyGestureEvent.ACTION_GESTURE_COMPLETE;
+        private int mDisplayId = Display.DEFAULT_DISPLAY;
+        private int mFlags = 0;
+
+        /**
+         * @see KeyGestureEvent#getDeviceId()
+         */
+        public Builder setDeviceId(int deviceId) {
+            mDeviceId = deviceId;
+            return this;
+        }
+
+        /**
+         * @see KeyGestureEvent#getKeycodes()
+         */
+        public Builder setKeycodes(@NonNull int[] keycodes) {
+            mKeycodes = keycodes;
+            return this;
+        }
+
+        /**
+         * @see KeyGestureEvent#getModifierState()
+         */
+        public Builder setModifierState(int modifierState) {
+            mModifierState = modifierState;
+            return this;
+        }
+
+        /**
+         * @see KeyGestureEvent#getKeyGestureType()
+         */
+        public Builder setKeyGestureType(@KeyGestureEvent.KeyGestureType int keyGestureType) {
+            mKeyGestureType = keyGestureType;
+            return this;
+        }
+
+        /**
+         * @see KeyGestureEvent#getAction()
+         */
+        public Builder setAction(int action) {
+            mAction = action;
+            return this;
+        }
+
+        /**
+         * @see KeyGestureEvent#getDisplayId()
+         */
+        public Builder setDisplayId(int displayId) {
+            mDisplayId = displayId;
+            return this;
+        }
+
+        /**
+         * @see KeyGestureEvent#getFlags()
+         */
+        public Builder setFlags(int flags) {
+            mFlags = flags;
+            return this;
+        }
+
+        /**
+         * Build {@link KeyGestureEvent}
+         */
+        public KeyGestureEvent build() {
+            AidlKeyGestureEvent event = new AidlKeyGestureEvent();
+            event.deviceId = mDeviceId;
+            event.keycodes = mKeycodes;
+            event.modifierState = mModifierState;
+            event.gestureType = mKeyGestureType;
+            event.action = mAction;
+            event.displayId = mDisplayId;
+            event.flags = mFlags;
+            return new KeyGestureEvent(event);
         }
     }
 
-    @DataClass.Generated.Member
-    public KeyGestureEvent(
-            int deviceId,
-            @NonNull int[] keycodes,
-            int modifierState,
-            @KeyGestureType int keyGestureType) {
-        this.mDeviceId = deviceId;
-        this.mKeycodes = keycodes;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mKeycodes);
-        this.mModifierState = modifierState;
-        this.mKeyGestureType = keyGestureType;
-
-        if (!(mKeyGestureType == KEY_GESTURE_TYPE_UNSPECIFIED)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_HOME)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_RECENT_APPS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_BACK)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_APP_SWITCH)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_ASSISTANT)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_TASKBAR)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_TAKE_SCREENSHOT)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_BRIGHTNESS_UP)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_BRIGHTNESS_DOWN)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_UP)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_DOWN)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_VOLUME_MUTE)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_ALL_APPS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_SEARCH)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LANGUAGE_SWITCH)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_SYSTEM_MUTE)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LOCK_SCREEN)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_OPEN_NOTES)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_TOGGLE_POWER)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_SYSTEM_NAVIGATION)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_SLEEP)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_WAKEUP)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_MEDIA_KEY)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_DESKTOP_MODE)
-                && !(mKeyGestureType == KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION)) {
-            throw new java.lang.IllegalArgumentException(
-                    "keyGestureType was " + mKeyGestureType + " but must be one of: "
-                            + "KEY_GESTURE_TYPE_UNSPECIFIED(" + KEY_GESTURE_TYPE_UNSPECIFIED + "), "
-                            + "KEY_GESTURE_TYPE_HOME(" + KEY_GESTURE_TYPE_HOME + "), "
-                            + "KEY_GESTURE_TYPE_RECENT_APPS(" + KEY_GESTURE_TYPE_RECENT_APPS + "), "
-                            + "KEY_GESTURE_TYPE_BACK(" + KEY_GESTURE_TYPE_BACK + "), "
-                            + "KEY_GESTURE_TYPE_APP_SWITCH(" + KEY_GESTURE_TYPE_APP_SWITCH + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT(" + KEY_GESTURE_TYPE_LAUNCH_ASSISTANT + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT(" + KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS(" + KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS + "), "
-                            + "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL(" + KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL + "), "
-                            + "KEY_GESTURE_TYPE_TOGGLE_TASKBAR(" + KEY_GESTURE_TYPE_TOGGLE_TASKBAR + "), "
-                            + "KEY_GESTURE_TYPE_TAKE_SCREENSHOT(" + KEY_GESTURE_TYPE_TAKE_SCREENSHOT + "), "
-                            + "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER(" + KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER + "), "
-                            + "KEY_GESTURE_TYPE_BRIGHTNESS_UP(" + KEY_GESTURE_TYPE_BRIGHTNESS_UP + "), "
-                            + "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN(" + KEY_GESTURE_TYPE_BRIGHTNESS_DOWN + "), "
-                            + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP + "), "
-                            + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN + "), "
-                            + "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE(" + KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE + "), "
-                            + "KEY_GESTURE_TYPE_VOLUME_UP(" + KEY_GESTURE_TYPE_VOLUME_UP + "), "
-                            + "KEY_GESTURE_TYPE_VOLUME_DOWN(" + KEY_GESTURE_TYPE_VOLUME_DOWN + "), "
-                            + "KEY_GESTURE_TYPE_VOLUME_MUTE(" + KEY_GESTURE_TYPE_VOLUME_MUTE + "), "
-                            + "KEY_GESTURE_TYPE_ALL_APPS(" + KEY_GESTURE_TYPE_ALL_APPS + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_SEARCH(" + KEY_GESTURE_TYPE_LAUNCH_SEARCH + "), "
-                            + "KEY_GESTURE_TYPE_LANGUAGE_SWITCH(" + KEY_GESTURE_TYPE_LANGUAGE_SWITCH + "), "
-                            + "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS(" + KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS + "), "
-                            + "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK(" + KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK + "), "
-                            + "KEY_GESTURE_TYPE_SYSTEM_MUTE(" + KEY_GESTURE_TYPE_SYSTEM_MUTE + "), "
-                            + "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION(" + KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION + "), "
-                            + "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS(" + KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS + "), "
-                            + "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT(" + KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT + "), "
-                            + "KEY_GESTURE_TYPE_LOCK_SCREEN(" + KEY_GESTURE_TYPE_LOCK_SCREEN + "), "
-                            + "KEY_GESTURE_TYPE_OPEN_NOTES(" + KEY_GESTURE_TYPE_OPEN_NOTES + "), "
-                            + "KEY_GESTURE_TYPE_TOGGLE_POWER(" + KEY_GESTURE_TYPE_TOGGLE_POWER + "), "
-                            + "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION(" + KEY_GESTURE_TYPE_SYSTEM_NAVIGATION + "), "
-                            + "KEY_GESTURE_TYPE_SLEEP(" + KEY_GESTURE_TYPE_SLEEP + "), "
-                            + "KEY_GESTURE_TYPE_WAKEUP(" + KEY_GESTURE_TYPE_WAKEUP + "), "
-                            + "KEY_GESTURE_TYPE_MEDIA_KEY(" + KEY_GESTURE_TYPE_MEDIA_KEY + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS(" + KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS + "), "
-                            + "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME(" + KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME + "), "
-                            + "KEY_GESTURE_TYPE_DESKTOP_MODE(" + KEY_GESTURE_TYPE_DESKTOP_MODE + "), "
-                            + "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION(" + KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION + ")");
-        }
-
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    @DataClass.Generated.Member
     public int getDeviceId() {
-        return mDeviceId;
+        return mKeyGestureEvent.deviceId;
     }
 
-    @DataClass.Generated.Member
     public @NonNull int[] getKeycodes() {
-        return mKeycodes;
+        return mKeyGestureEvent.keycodes;
     }
 
-    @DataClass.Generated.Member
     public int getModifierState() {
-        return mModifierState;
+        return mKeyGestureEvent.modifierState;
     }
 
-    @DataClass.Generated.Member
     public @KeyGestureType int getKeyGestureType() {
-        return mKeyGestureType;
+        return mKeyGestureEvent.gestureType;
+    }
+
+    public int getAction() {
+        return mKeyGestureEvent.action;
+    }
+
+    public int getDisplayId() {
+        return mKeyGestureEvent.displayId;
+    }
+
+    public int getFlags() {
+        return mKeyGestureEvent.flags;
+    }
+
+    public boolean isCancelled() {
+        return (mKeyGestureEvent.flags & FLAG_CANCELLED) != 0;
     }
 
     @Override
-    @DataClass.Generated.Member
     public String toString() {
-        // You can override field toString logic by defining methods like:
-        // String fieldNameToString() { ... }
-
-        return "KeyGestureEvent { " +
-                "deviceId = " + mDeviceId + ", " +
-                "keycodes = " + java.util.Arrays.toString(mKeycodes) + ", " +
-                "modifierState = " + mModifierState + ", " +
-                "keyGestureType = " + keyGestureTypeToString(mKeyGestureType) +
-        " }";
+        return "KeyGestureEvent { "
+                + "deviceId = " + mKeyGestureEvent.deviceId + ", "
+                + "keycodes = " + java.util.Arrays.toString(mKeyGestureEvent.keycodes) + ", "
+                + "modifierState = " + mKeyGestureEvent.modifierState + ", "
+                + "keyGestureType = " + keyGestureTypeToString(mKeyGestureEvent.gestureType) + ", "
+                + "action = " + mKeyGestureEvent.action + ", "
+                + "displayId = " + mKeyGestureEvent.displayId + ", "
+                + "flags = " + mKeyGestureEvent.flags
+                + " }";
     }
 
     @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(KeyGestureEvent other) { ... }
-        // boolean fieldNameEquals(FieldType otherValue) { ... }
-
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
-        @SuppressWarnings("unchecked")
         KeyGestureEvent that = (KeyGestureEvent) o;
-        //noinspection PointlessBooleanExpression
-        return true
-                && mDeviceId == that.mDeviceId
-                && java.util.Arrays.equals(mKeycodes, that.mKeycodes)
-                && mModifierState == that.mModifierState
-                && mKeyGestureType == that.mKeyGestureType;
+        return mKeyGestureEvent.deviceId == that.mKeyGestureEvent.deviceId
+                && java.util.Arrays.equals(mKeyGestureEvent.keycodes, that.mKeyGestureEvent.keycodes)
+                && mKeyGestureEvent.modifierState == that.mKeyGestureEvent.modifierState
+                && mKeyGestureEvent.gestureType == that.mKeyGestureEvent.gestureType
+                && mKeyGestureEvent.action == that.mKeyGestureEvent.action
+                && mKeyGestureEvent.displayId == that.mKeyGestureEvent.displayId
+                && mKeyGestureEvent.flags == that.mKeyGestureEvent.flags;
     }
 
     @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 + mDeviceId;
-        _hash = 31 * _hash + java.util.Arrays.hashCode(mKeycodes);
-        _hash = 31 * _hash + mModifierState;
-        _hash = 31 * _hash + mKeyGestureType;
+        _hash = 31 * _hash + mKeyGestureEvent.deviceId;
+        _hash = 31 * _hash + java.util.Arrays.hashCode(mKeyGestureEvent.keycodes);
+        _hash = 31 * _hash + mKeyGestureEvent.modifierState;
+        _hash = 31 * _hash + mKeyGestureEvent.gestureType;
+        _hash = 31 * _hash + mKeyGestureEvent.action;
+        _hash = 31 * _hash + mKeyGestureEvent.displayId;
+        _hash = 31 * _hash + mKeyGestureEvent.flags;
         return _hash;
     }
 
-    @DataClass.Generated(
-            time = 1723409092192L,
-            codegenVersion = "1.0.23",
-            sourceFile = "frameworks/base/core/java/android/hardware/input/KeyGestureEvent.java",
-            inputSignatures = "private final  int mDeviceId\nprivate final @android.annotation.NonNull int[] mKeycodes\nprivate final  int mModifierState\nprivate final @android.hardware.input.KeyGestureEvent.KeyGestureType int mKeyGestureType\npublic static final  int KEY_GESTURE_TYPE_UNSPECIFIED\npublic static final  int KEY_GESTURE_TYPE_HOME\npublic static final  int KEY_GESTURE_TYPE_RECENT_APPS\npublic static final  int KEY_GESTURE_TYPE_BACK\npublic static final  int KEY_GESTURE_TYPE_APP_SWITCH\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_ASSISTANT\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS\npublic static final  int KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL\npublic static final  int KEY_GESTURE_TYPE_TOGGLE_TASKBAR\npublic static final  int KEY_GESTURE_TYPE_TAKE_SCREENSHOT\npublic static final  int KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER\npublic static final  int KEY_GESTURE_TYPE_BRIGHTNESS_UP\npublic static final  int KEY_GESTURE_TYPE_BRIGHTNESS_DOWN\npublic static final  int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP\npublic static final  int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN\npublic static final  int KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE\npublic static final  int KEY_GESTURE_TYPE_VOLUME_UP\npublic static final  int KEY_GESTURE_TYPE_VOLUME_DOWN\npublic static final  int KEY_GESTURE_TYPE_VOLUME_MUTE\npublic static final  int KEY_GESTURE_TYPE_ALL_APPS\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_SEARCH\npublic static final  int KEY_GESTURE_TYPE_LANGUAGE_SWITCH\npublic static final  int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS\npublic static final  int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK\npublic static final  int KEY_GESTURE_TYPE_SYSTEM_MUTE\npublic static final  int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION\npublic static final  int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS\npublic static final  int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT\npublic static final  int KEY_GESTURE_TYPE_LOCK_SCREEN\npublic static final  int KEY_GESTURE_TYPE_OPEN_NOTES\npublic static final  int KEY_GESTURE_TYPE_TOGGLE_POWER\npublic static final  int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION\npublic static final  int KEY_GESTURE_TYPE_SLEEP\npublic static final  int KEY_GESTURE_TYPE_WAKEUP\npublic static final  int KEY_GESTURE_TYPE_MEDIA_KEY\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS\npublic static final  int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME\npublic static final  int KEY_GESTURE_TYPE_DESKTOP_MODE\npublic static final  int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION\nclass KeyGestureEvent extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
-    @Deprecated
-    private void __metadata() {}
+    /**
+     * Convert KeyGestureEvent type to corresponding log event got KeyboardSystemsEvent
+     */
+    public static int keyGestureTypeToLogEvent(@KeyGestureType int value) {
+        switch (value) {
+            case KEY_GESTURE_TYPE_HOME:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME;
+            case KEY_GESTURE_TYPE_RECENT_APPS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS;
+            case KEY_GESTURE_TYPE_BACK:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK;
+            case KEY_GESTURE_TYPE_APP_SWITCH:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH;
+            case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT;
+            case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT;
+            case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS;
+            case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL;
+            case KEY_GESTURE_TYPE_TOGGLE_TASKBAR:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR;
+            case KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT;
+            case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER;
+            case KEY_GESTURE_TYPE_BRIGHTNESS_UP:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP;
+            case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN;
+            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP;
+            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN;
+            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE;
+            case KEY_GESTURE_TYPE_VOLUME_UP:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP;
+            case KEY_GESTURE_TYPE_VOLUME_DOWN:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN;
+            case KEY_GESTURE_TYPE_VOLUME_MUTE:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE;
+            case KEY_GESTURE_TYPE_ALL_APPS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS;
+            case KEY_GESTURE_TYPE_LAUNCH_SEARCH:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH;
+            case KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH;
+            case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS;
+            case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK;
+            case KEY_GESTURE_TYPE_SYSTEM_MUTE:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE;
+            case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION;
+            case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS;
+            case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT;
+            case KEY_GESTURE_TYPE_LOCK_SCREEN:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN;
+            case KEY_GESTURE_TYPE_OPEN_NOTES:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES;
+            case KEY_GESTURE_TYPE_TOGGLE_POWER:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER;
+            case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION;
+            case KEY_GESTURE_TYPE_SLEEP:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP;
+            case KEY_GESTURE_TYPE_WAKEUP:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP;
+            case KEY_GESTURE_TYPE_MEDIA_KEY:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER;
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS;
+            case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME;
+            case KEY_GESTURE_TYPE_DESKTOP_MODE:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE;
+            case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION;
+            default:
+                return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
+        }
+    }
 
-
-    //@formatter:on
-    // End of generated code
-
+    private static String keyGestureTypeToString(@KeyGestureType int value) {
+        switch (value) {
+            case KEY_GESTURE_TYPE_UNSPECIFIED:
+                return "KEY_GESTURE_TYPE_UNSPECIFIED";
+            case KEY_GESTURE_TYPE_HOME:
+                return "KEY_GESTURE_TYPE_HOME";
+            case KEY_GESTURE_TYPE_RECENT_APPS:
+                return "KEY_GESTURE_TYPE_RECENT_APPS";
+            case KEY_GESTURE_TYPE_BACK:
+                return "KEY_GESTURE_TYPE_BACK";
+            case KEY_GESTURE_TYPE_APP_SWITCH:
+                return "KEY_GESTURE_TYPE_APP_SWITCH";
+            case KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+                return "KEY_GESTURE_TYPE_LAUNCH_ASSISTANT";
+            case KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
+                return "KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT";
+            case KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
+                return "KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS";
+            case KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
+                return "KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL";
+            case KEY_GESTURE_TYPE_TOGGLE_TASKBAR:
+                return "KEY_GESTURE_TYPE_TOGGLE_TASKBAR";
+            case KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
+                return "KEY_GESTURE_TYPE_TAKE_SCREENSHOT";
+            case KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
+                return "KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER";
+            case KEY_GESTURE_TYPE_BRIGHTNESS_UP:
+                return "KEY_GESTURE_TYPE_BRIGHTNESS_UP";
+            case KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
+                return "KEY_GESTURE_TYPE_BRIGHTNESS_DOWN";
+            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+                return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP";
+            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+                return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN";
+            case KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+                return "KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE";
+            case KEY_GESTURE_TYPE_VOLUME_UP:
+                return "KEY_GESTURE_TYPE_VOLUME_UP";
+            case KEY_GESTURE_TYPE_VOLUME_DOWN:
+                return "KEY_GESTURE_TYPE_VOLUME_DOWN";
+            case KEY_GESTURE_TYPE_VOLUME_MUTE:
+                return "KEY_GESTURE_TYPE_VOLUME_MUTE";
+            case KEY_GESTURE_TYPE_ALL_APPS:
+                return "KEY_GESTURE_TYPE_ALL_APPS";
+            case KEY_GESTURE_TYPE_LAUNCH_SEARCH:
+                return "KEY_GESTURE_TYPE_LAUNCH_SEARCH";
+            case KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
+                return "KEY_GESTURE_TYPE_LANGUAGE_SWITCH";
+            case KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
+                return "KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS";
+            case KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+                return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK";
+            case KEY_GESTURE_TYPE_SYSTEM_MUTE:
+                return "KEY_GESTURE_TYPE_SYSTEM_MUTE";
+            case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
+                return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION";
+            case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
+                return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS";
+            case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
+                return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT";
+            case KEY_GESTURE_TYPE_LOCK_SCREEN:
+                return "KEY_GESTURE_TYPE_LOCK_SCREEN";
+            case KEY_GESTURE_TYPE_OPEN_NOTES:
+                return "KEY_GESTURE_TYPE_OPEN_NOTES";
+            case KEY_GESTURE_TYPE_TOGGLE_POWER:
+                return "KEY_GESTURE_TYPE_TOGGLE_POWER";
+            case KEY_GESTURE_TYPE_SYSTEM_NAVIGATION:
+                return "KEY_GESTURE_TYPE_SYSTEM_NAVIGATION";
+            case KEY_GESTURE_TYPE_SLEEP:
+                return "KEY_GESTURE_TYPE_SLEEP";
+            case KEY_GESTURE_TYPE_WAKEUP:
+                return "KEY_GESTURE_TYPE_WAKEUP";
+            case KEY_GESTURE_TYPE_MEDIA_KEY:
+                return "KEY_GESTURE_TYPE_MEDIA_KEY";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER";
+            case KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS:
+                return "KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS";
+            case KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME:
+                return "KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME";
+            case KEY_GESTURE_TYPE_DESKTOP_MODE:
+                return "KEY_GESTURE_TYPE_DESKTOP_MODE";
+            case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
+                return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION";
+            default:
+                return Integer.toHexString(value);
+        }
+    }
 }
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 360b2ac..73cdd56 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -33,7 +33,7 @@
      * if creation is supported but fails.
      */
     IHintSession createHintSessionWithConfig(in IBinder token, in int[] threadIds,
-            in long durationNanos, in SessionTag tag, out @nullable SessionConfig config);
+            in long durationNanos, in SessionTag tag, out SessionConfig config);
 
     /**
      * Get preferred rate limit in nanoseconds.
@@ -48,6 +48,6 @@
      *
      * Throws IllegalStateException if FMQ channel creation fails.
      */
-    ChannelConfig getSessionChannel(in IBinder token);
+    @nullable ChannelConfig getSessionChannel(in IBinder token);
     oneway void closeSessionChannel();
 }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 3b2041b..346ee7c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -589,6 +589,12 @@
      **/
     public static final int THREAD_GROUP_RESTRICTED = 7;
 
+    /**
+     * Thread group for foreground apps in multi-window mode
+     * @hide
+     **/
+    public static final int THREAD_GROUP_FOREGROUND_WINDOW = 8;
+
     /** @hide */
     public static final int SIGNAL_DEFAULT = 0;
     public static final int SIGNAL_QUIT = 3;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f1ec0e4e..a4a7a98 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1539,10 +1539,19 @@
      * Specifies that the managed profile is not allowed to have unified lock screen challenge with
      * the primary user.
      *
-     * <p><strong>Note:</strong> Setting this restriction alone doesn't automatically set a
-     * separate challenge. Profile owner can ask the user to set a new password using
-     * {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} and verify it using
-     * {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}.
+     * <p>To ensure that there is a separate work profile password, IT admins
+     * have to:
+     * <ol>
+     *   <li>Enforce {@link UserManager#DISALLOW_UNIFIED_PASSWORD}</li>
+     *   <li>Verify that {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}
+     *       returns true. This indicates that there is now a separate work
+     *       profile password configured and the set up is completed.</li>
+     *   <li>In case {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}
+     *       returns false, invoke {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD}
+     *       intent and then verify again
+     *       {@link DevicePolicyManager#isUsingUnifiedPassword(ComponentName)}.</li>
+     * </ol>
+     * </p>
      *
      * <p>Can be set by profile owners. It only has effect on managed profiles when set by managed
      * profile owner. Has no effect on non-managed profiles or users.
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 4357703..39bd15c 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -107,14 +107,6 @@
 }
 
 flag {
-    name: "adpf_fmq_eager_send"
-    namespace: "game"
-    description: "Guards the use of an eager-sending optimization in FMQ for low-latency messages"
-    is_fixed_read_only: true
-    bug: "315894228"
-}
-
-flag {
     name: "adpf_hwui_gpu"
     namespace: "game"
     description: "Guards use of the FMQ channel for ADPF"
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index bc6c570..e6e5a27 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -30,17 +30,13 @@
 
 import android.annotation.Nullable;
 import android.content.res.Resources;
-import android.os.SystemProperties;
 import android.os.VibrationAttributes;
 import android.os.Vibrator;
 import android.os.Vibrator.VibrationIntensity;
 import android.util.IndentingPrintWriter;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.function.Function;
 
 /**
  * List of device-specific internal vibration configuration loaded from platform config.xml.
@@ -54,37 +50,6 @@
 public class VibrationConfig {
 
     /**
-     * The default gain to be applied between vibration scale levels.
-     *
-     * <p>Scale levels are defined as the difference between the user vibration intensity setting
-     * and the device default config for each usage. The intensity values are defined as one of
-     * Vibrator.VIBRATION_INTENSITY_*.
-     *
-     * <p>A user setting HIGH set on a device with default value LOW will cause the vibration
-     * intensity to be scaled up 2 levels, i.e. scale with a factor of gain^2. A system with 3
-     * intensities LOW, MEDIUM and HIGH has the following 5 scale levels:
-     *
-     * <ol>
-     *     <li>VERY_HIGH: user(HIGH) - device(LOW)
-     *     <li>HIGH: user(HIGH) - device(MEDIUM) / user(MEDIUM) - device(LOW)
-     *     <li>NONE: user == device
-     *     <li>LOW: user(MEDIUM) - device(HIGH) / user(LOW) - device(MEDIUM)
-     *     <li>VERY_LOW: user(LOW) - device(HIGH)
-     * </ol>
-     *
-     * <p>A device will only ever apply 3 out of these 5 levels based on the default intensity
-     * config set for each usage (e.g. config_default[Alarm|Ring|Notification]VibrationIntensity).
-     *
-     * <p>This value must be greater than 1. The {@link #DEFAULT_SCALE_LEVEL_GAIN} will be used if
-     * this property is undefined or invalid.
-     *
-     * @hide
-     */
-    @VisibleForTesting
-    static final String SCALE_LEVEL_GAIN_SYSTEM_PROPERTY =
-            "vendor.vibrator.scale.level.gain";
-
-    /**
      * Hardcoded default scale level gain to be applied between each scale level to define their
      * scale factor value.
      *
@@ -104,7 +69,7 @@
     private final int mRampDownDurationMs;
     private final int mRequestVibrationParamsTimeoutMs;
     private final int[] mRequestVibrationParamsForUsages;
-    private final float mDefaultVibrationScaleLevelGain;
+
     private final boolean mIgnoreVibrationsOnWirelessCharger;
 
     @VibrationIntensity
@@ -124,18 +89,8 @@
 
     /** @hide */
     public VibrationConfig(@Nullable Resources resources) {
-        this(resources, SystemProperties::get);
-    }
-
-    /** @hide */
-    @VisibleForTesting
-    public VibrationConfig(@Nullable Resources resources,
-            Function<String, String> systemPropertiesGetter) {
-        mDefaultVibrationAmplitude = loadInteger(resources,
-                com.android.internal.R.integer.config_defaultVibrationAmplitude,
-                DEFAULT_AMPLITUDE);
-        mDefaultVibrationScaleLevelGain = loadFloat(systemPropertiesGetter,
-                SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, DEFAULT_SCALE_LEVEL_GAIN);
+        mDefaultVibrationAmplitude = resources.getInteger(
+                com.android.internal.R.integer.config_defaultVibrationAmplitude);
         mHapticChannelMaxVibrationAmplitude = loadFloat(resources,
                 com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude);
         mRampDownDurationMs = loadInteger(resources,
@@ -180,15 +135,6 @@
         return res != null ? res.getFloat(resId) : 0f;
     }
 
-    private static float loadFloat(Function<String, String> systemPropertiesGetter,
-            String propertyKey, float defaultValue) {
-        try {
-            return Float.parseFloat(systemPropertiesGetter.apply(propertyKey));
-        } catch (Exception e) {
-            return defaultValue;
-        }
-    }
-
     private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) {
         return res != null ? res.getInteger(resId) : defaultValue;
     }
@@ -230,10 +176,8 @@
      * for each level.
      */
     public float getDefaultVibrationScaleLevelGain() {
-        if (mDefaultVibrationScaleLevelGain <= 1) {
-            return DEFAULT_SCALE_LEVEL_GAIN;
-        }
-        return mDefaultVibrationScaleLevelGain;
+        // TODO(b/356407380): add device config for this
+        return DEFAULT_SCALE_LEVEL_GAIN;
     }
 
     /**
@@ -326,7 +270,6 @@
         return "VibrationConfig{"
                 + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger
                 + ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude
-                + ", mDefaultVibrationScaleLevelGain=" + mDefaultVibrationScaleLevelGain
                 + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude
                 + ", mRampStepDurationMs=" + mRampStepDurationMs
                 + ", mRampDownDurationMs=" + mRampDownDurationMs
@@ -353,7 +296,6 @@
         pw.increaseIndent();
         pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger);
         pw.println("defaultVibrationAmplitude = " + mDefaultVibrationAmplitude);
-        pw.println("defaultVibrationScaleLevelGain = " + mDefaultVibrationScaleLevelGain);
         pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude);
         pw.println("rampStepDurationMs = " + mRampStepDurationMs);
         pw.println("rampDownDurationMs = " + mRampDownDurationMs);
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 6c486db..b0791e3 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -249,3 +249,19 @@
     description: "This flag is used to enabled the Wallet Role s icon fetching from manifest property"
     bug: "349942654"
 }
+
+flag {
+    name: "replace_body_sensors_permission_enabled"
+    is_exported: true
+    namespace: "android_health_services"
+    description: "This flag is used to enable replacing permission BODY_SENSORS(and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE(and READ_HEALTH_DATA_IN_BACKGROUND)"
+    bug: "364638912"
+}
+
+flag {
+    name: "appop_access_tracking_logging_enabled"
+    is_fixed_read_only: true
+    namespace: "permissions"
+    description: "Enables logging of the AppOp access tracking"
+    bug: "365584286"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0a05f70..e32625e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -17818,6 +17818,12 @@
         public static final String FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT =
                 "force_non_debuggable_final_build_for_compat";
 
+        /**
+         * Flag to enable the use of ApplicationInfo for getting not-launched status.
+         *
+         * @hide
+         */
+        public static final String ENABLE_USE_APP_INFO_NOT_LAUNCHED = "use_app_info_not_launched";
 
         /**
          * Current version of signed configuration applied.
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index f6f0eff..a86c961 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -99,3 +99,10 @@
   description: "Causes TrustManagerService to listen for credential attempts and ignore reports from upstream"
   bug: "323086607"
 }
+
+flag {
+    name: "clear_strong_auth_on_add_primary_credential"
+    namespace: "biometrics"
+    description: "Clear StrongAuth on add credential"
+    bug: "320817991"
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 82c52a6..f8c97eb 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -20,6 +20,8 @@
 import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
 import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API;
 
+import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API;
+
 import android.Manifest;
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -1499,6 +1501,15 @@
     }
 
     /**
+     * @return The highest possible HDR/SDR ratio. If {@link #isHdrSdrRatioAvailable()} returns
+     * false, this method returns 1.
+     */
+    @FlaggedApi(FLAG_HIGHEST_HDR_SDR_RATIO_API)
+    public float getHighestHdrSdrRatio() {
+        return mGlobal.getHighestHdrSdrRatio(mDisplayId);
+    }
+
+    /**
      * Sets the default {@link Display.Mode} to use for the display.  The display mode includes
      * preference for resolution and refresh rate.
      * If the mode specified is not supported by the display, then no mode change occurs.
diff --git a/core/java/android/webkit/WebViewUpdateManager.java b/core/java/android/webkit/WebViewUpdateManager.java
index 0eb71001..b9a5e4ae 100644
--- a/core/java/android/webkit/WebViewUpdateManager.java
+++ b/core/java/android/webkit/WebViewUpdateManager.java
@@ -43,22 +43,29 @@
     /**
      * Get the singleton instance of the manager.
      *
-     * This exists for the benefit of callsites without a {@link Context}; prefer
+     * <p>This exists for the benefit of callsites without a {@link Context}; prefer
      * {@link Context#getSystemService(Class)} otherwise.
      *
-     * This can only be used on devices with {@link PackageManager#FEATURE_WEBVIEW}.
+     * <p>This must only be called on devices with {@link PackageManager#FEATURE_WEBVIEW},
+     * and will WTF or throw {@link UnsupportedOperationException} otherwise.
      */
     @SuppressLint("ManagerLookup") // service opts in to getSystemServiceWithNoContext()
     @RequiresFeature(PackageManager.FEATURE_WEBVIEW)
-    public static @Nullable WebViewUpdateManager getInstance() {
-        return (WebViewUpdateManager) SystemServiceRegistry.getSystemServiceWithNoContext(
-                Context.WEBVIEW_UPDATE_SERVICE);
+    public static @NonNull WebViewUpdateManager getInstance() {
+        WebViewUpdateManager manager =
+                (WebViewUpdateManager) SystemServiceRegistry.getSystemServiceWithNoContext(
+                        Context.WEBVIEW_UPDATE_SERVICE);
+        if (manager == null) {
+            throw new UnsupportedOperationException("WebView not supported by device");
+        } else {
+            return manager;
+        }
     }
 
     /**
      * Block until system-level WebView preparations are complete.
      *
-     * This also makes the current WebView provider package visible to the caller.
+     * <p>This also makes the current WebView provider package visible to the caller.
      *
      * @return the status of WebView preparation and the current provider package.
      */
@@ -86,7 +93,7 @@
     /**
      * Get the complete list of supported WebView providers for this device.
      *
-     * This includes all configured providers, regardless of whether they are currently available
+     * <p>This includes all configured providers, regardless of whether they are currently available
      * or valid.
      */
     @SuppressLint({"ParcelableList", "ArrayReturn"})
@@ -101,13 +108,15 @@
     /**
      * Get the list of currently-valid WebView providers for this device.
      *
-     * This only includes providers that are currently present on the device and meet the validity
-     * criteria (signature, version, etc), but does not check if the provider is installed and
-     * enabled for all users.
+     * <p>This only includes providers that are currently present on the device and meet the
+     * validity criteria (signature, version, etc), but does not check if the provider is installed
+     * and enabled for all users.
+     *
+     * <p>Note that this will be filtered by the caller's package visibility; callers should
+     * have QUERY_ALL_PACKAGES permission to ensure that the list is complete.
      */
     @SuppressLint({"ParcelableList", "ArrayReturn"})
-    @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS,
-            android.Manifest.permission.QUERY_ALL_PACKAGES})
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     public @NonNull WebViewProviderInfo[] getValidWebViewPackages() {
         try {
             return mService.getValidWebViewPackages();
@@ -132,7 +141,7 @@
     /**
      * Ask the system to switch to a specific WebView implementation if possible.
      *
-     * This choice will be stored persistently.
+     * <p>This choice will be stored persistently.
      *
      * @param newProvider the package name to use.
      * @return the package name which is now in use, which may not be the
@@ -162,7 +171,7 @@
     /**
      * Get the WebView provider which will be used if no explicit choice has been made.
      *
-     * The default provider is not guaranteed to be a valid/usable WebView implementation.
+     * <p>The default provider is not guaranteed to be a valid/usable WebView implementation.
      *
      * @return the default WebView provider.
      */
diff --git a/core/java/android/webkit/WebViewUpdateService.java b/core/java/android/webkit/WebViewUpdateService.java
index 01af182..644d917 100644
--- a/core/java/android/webkit/WebViewUpdateService.java
+++ b/core/java/android/webkit/WebViewUpdateService.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.RemoteException;
@@ -54,7 +55,11 @@
 
     /**
      * Fetch all packages that could potentially implement WebView and are currently valid.
+     *
+     * <p>Note that this will be filtered by the caller's package visibility; callers should
+     * have QUERY_ALL_PACKAGES permission to ensure that the list is complete.
      */
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     public static WebViewProviderInfo[] getValidWebViewPackages() {
         if (Flags.updateServiceIpcWrapper()) {
             if (WebViewFactory.isWebViewSupported()) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 89ea852..e1154ca 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -83,6 +83,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.system.Os;
 import android.text.TextUtils;
@@ -7003,6 +7004,18 @@
 
     private View inflateView(Context context, RemoteViews rv, @Nullable ViewGroup parent,
             @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
+        try {
+            Trace.beginSection(rv.hasDrawInstructions()
+                    ? "RemoteViews#inflateViewWithDrawInstructions"
+                    : "RemoteViews#inflateView");
+            return inflateViewInternal(context, rv, parent, applyThemeResId, colorResources);
+        } finally {
+            Trace.endSection();
+        }
+    }
+
+    private View inflateViewInternal(Context context, RemoteViews rv, @Nullable ViewGroup parent,
+            @StyleRes int applyThemeResId, @Nullable ColorResources colorResources) {
         // RemoteViews may be built by an application installed in another
         // user. So build a context that loads resources from that user but
         // still returns the current users userId so settings like data / time formats
@@ -7169,10 +7182,17 @@
                 if (mRV.mActions != null) {
                     int count = mRV.mActions.size();
                     mActions = new Action[count];
-                    for (int i = 0; i < count && !isCancelled(); i++) {
-                        // TODO: check if isCancelled in nested views.
-                        mActions[i] = mRV.mActions.get(i)
-                                .initActionAsync(mTree, mParent, mApplyParams);
+                    try {
+                        Trace.beginSection(hasDrawInstructions()
+                                ? "RemoteViews#initActionAsyncWithDrawInstructions"
+                                : "RemoteViews#initActionAsync");
+                        for (int i = 0; i < count && !isCancelled(); i++) {
+                            // TODO: check if isCancelled in nested views.
+                            mActions[i] = mRV.mActions.get(i)
+                                    .initActionAsync(mTree, mParent, mApplyParams);
+                        }
+                    } finally {
+                        Trace.endSection();
                     }
                 } else {
                     mActions = null;
@@ -7194,13 +7214,19 @@
 
                 try {
                     if (mActions != null) {
-
                         ActionApplyParams applyParams = mApplyParams.clone();
                         if (applyParams.handler == null) {
                             applyParams.handler = DEFAULT_INTERACTION_HANDLER;
                         }
-                        for (Action a : mActions) {
-                            a.apply(viewTree.mRoot, mParent, applyParams);
+                        try {
+                            Trace.beginSection(hasDrawInstructions()
+                                    ? "RemoteViews#applyActionsAsyncWithDrawInstructions"
+                                    : "RemoteViews#applyActionsAsync");
+                            for (Action a : mActions) {
+                                a.apply(viewTree.mRoot, mParent, applyParams);
+                            }
+                        } finally {
+                            Trace.endSection();
                         }
                     }
                     // If the parent of the view is has is a root, resolve the recycling.
@@ -7387,8 +7413,15 @@
         }
         if (mActions != null) {
             final int count = mActions.size();
-            for (int i = 0; i < count; i++) {
-                mActions.get(i).apply(v, parent, params);
+            try {
+                Trace.beginSection(hasDrawInstructions()
+                        ? "RemoteViews#applyActionsWithDrawInstructions"
+                        : "RemoteViews#applyActions");
+                for (int i = 0; i < count; i++) {
+                    mActions.get(i).apply(v, parent, params);
+                }
+            } finally {
+                Trace.endSection();
             }
         }
     }
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index bccee92..0632a37 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -76,7 +76,7 @@
      * @param callback The callback to be registered. If the callback instance has been already
      *                 registered, the existing instance (no matter its priority) will be
      *                 unregistered and registered again.
-     * @throws {@link IllegalArgumentException} if the priority is negative.
+     * @throws IllegalArgumentException if the priority is negative.
      */
     @SuppressLint({"ExecutorRegistration"})
     void registerOnBackInvokedCallback(
diff --git a/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java b/core/java/android/window/flags/DesktopModeFlags.java
similarity index 82%
rename from services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java
rename to core/java/android/window/flags/DesktopModeFlags.java
index d33313e..5c53d66 100644
--- a/services/core/java/com/android/server/wm/utils/DesktopModeFlagsUtil.java
+++ b/core/java/android/window/flags/DesktopModeFlags.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.utils;
-
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET;
+package android.window.flags;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -28,18 +26,18 @@
 import java.util.function.Supplier;
 
 /**
- * Util to check desktop mode flags state.
+ * Checks desktop mode flag state.
  *
- * This utility is used to allow developer option toggles to override flags related to desktop
- * windowing.
+ * <p>This enum provides a centralized way to control the behavior of flags related to desktop
+ * windowing features which are aiming for developer preview before their release. It allows
+ * developer option to override the default behavior of these flags.
  *
- * Computes whether Desktop Windowing related flags should be enabled by using the aconfig flag
- * value and the developer option override state (if applicable).
+ * <p>NOTE: Flags should only be added to this enum when they have received Product and UX
+ * alignment that the feature is ready for developer preview, otherwise just do a flag check.
  *
- * This is a partial copy of {@link com.android.wm.shell.shared.desktopmode.DesktopModeFlags} which
- * is to be used in WM core.
+ * @hide
  */
-public enum DesktopModeFlagsUtil {
+public enum DesktopModeFlags {
     // All desktop mode related flags to be overridden by developer option toggle will be added here
     DESKTOP_WINDOWING_MODE(
             Flags::enableDesktopWindowingMode, /* shouldOverrideByDevOption= */ true),
@@ -55,7 +53,7 @@
     // be refreshed only on reboots as overridden state is expected to take effect on reboots.
     private static ToggleOverride sCachedToggleOverride;
 
-    DesktopModeFlagsUtil(Supplier<Boolean> flagFunction, boolean shouldOverrideByDevOption) {
+    DesktopModeFlags(Supplier<Boolean> flagFunction, boolean shouldOverrideByDevOption) {
         this.mFlagFunction = flagFunction;
         this.mShouldOverrideByDevOption = shouldOverrideByDevOption;
     }
@@ -101,13 +99,13 @@
         int settingValue = Settings.Global.getInt(
                 context.getContentResolver(),
                 Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
-                OVERRIDE_UNSET.getSetting()
+                ToggleOverride.OVERRIDE_UNSET.getSetting()
         );
-        return ToggleOverride.fromSetting(settingValue, OVERRIDE_UNSET);
+        return ToggleOverride.fromSetting(settingValue, ToggleOverride.OVERRIDE_UNSET);
     }
 
     /** Override state of desktop mode developer option toggle. */
-    enum ToggleOverride {
+    private enum ToggleOverride {
         OVERRIDE_UNSET,
         OVERRIDE_OFF,
         OVERRIDE_ON;
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 8e81951..6e89c49 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -215,6 +215,13 @@
 }
 
 flag {
+    name: "enable_desktop_windowing_exit_transitions"
+    namespace: "lse_desktop_experience"
+    description: "Enables exit desktop windowing transition & motion polish changes"
+    bug: "353650462"
+}
+
+flag {
     name: "enable_compat_ui_visibility_status"
     namespace: "lse_desktop_experience"
     description: "Enables the tracking of the status for compat ui elements."
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index a786fc2..69b91fd 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -144,6 +144,13 @@
 }
 
 flag {
+  name: "universal_resizable_by_default"
+  namespace: "windowing_frontend"
+  description: "The orientation, aspect ratio, resizability of activity will follow system behavior by default"
+  bug: "357141415"
+}
+
+flag {
   name: "respect_non_top_visible_fixed_orientation"
   namespace: "windowing_frontend"
   description: "If top activity is not opaque, respect the fixed orientation of activity behind it"
@@ -181,6 +188,17 @@
 }
 
 flag {
+  name: "update_dims_when_window_shown"
+  namespace: "windowing_frontend"
+  description: "Check if we need to update dim layers when a new window draws the first frame"
+  bug: "327332488"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
     name: "release_snapshot_aggressively"
     namespace: "windowing_frontend"
     description: "Actively release task snapshot memory"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 8077a55..13648de 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -115,3 +115,10 @@
     bug: "289875940"
     is_fixed_read_only: true
 }
+
+flag {
+    namespace: "windowing_sdk"
+    name: "touch_pass_through_opt_in"
+    description: "Requires apps to opt-in to overlay pass through touches and provide APIs to opt-in"
+    bug: "358129114"
+}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index e5ac0e1..49191ee 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -404,6 +404,11 @@
                 return;
             }
             break;
+        case SP_FOREGROUND_WINDOW:
+            if (!CgroupGetAttributePath("HighCapacityWICPUs", &filename)) {
+                return;
+            }
+            break;
         case SP_TOP_APP:
             if (!CgroupGetAttributePath("MaxCapacityCPUs", &filename)) {
                 return;
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index c1022a5..664d54d 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -43,3 +43,10 @@
     name: "bugreport_artifacts",
     srcs: ["config/test-sysconfig.xml"],
 }
+
+test_module_config {
+    name: "BugreportManagerTestCases_android_server_os",
+    base: "BugreportManagerTestCases",
+    test_suites: ["general-tests"],
+    exclude_annotations: ["androidx.test.filters.LargeTest"],
+}
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 5111d2d..d98836f 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -303,6 +303,7 @@
     name: "FrameworksCoreTests_Presubmit",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -313,6 +314,7 @@
     name: "FrameworksCoreTests_inputmethod",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -327,6 +329,7 @@
     name: "FrameworksCoreTests_context",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -337,6 +340,7 @@
     name: "FrameworksCoreTests_keyguard_manager",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -347,6 +351,7 @@
     name: "FrameworksCoreTests_property_invalidated_cache",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -357,6 +362,7 @@
     name: "FrameworksCoreTests_android_content",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -371,6 +377,7 @@
     name: "FrameworksCoreTests_sqlite",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -381,6 +388,7 @@
     name: "FrameworksCoreTests_android_net",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -392,6 +400,7 @@
     name: "FrameworksCoreTests_battery_stats",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -403,6 +412,7 @@
     name: "FrameworksCoreTests_environment",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -413,6 +423,7 @@
     name: "FrameworksCoreTests_util_data_charset",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -426,6 +437,7 @@
     name: "FrameworksCoreTests_xml",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -439,6 +451,7 @@
     name: "FrameworksCoreTests_util_apk",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -449,6 +462,7 @@
     name: "FrameworksCoreTests_textclassifier",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -460,6 +474,7 @@
     name: "FrameworksCoreTests_internal_app",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -474,6 +489,7 @@
     name: "FrameworksCoreTests_internal_content",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -484,6 +500,7 @@
     name: "FrameworksCoreTests_internal_infra",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -494,6 +511,7 @@
     name: "FrameworksCoreTests_internal_jank",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -504,6 +522,7 @@
     name: "FrameworksCoreTests_internal_os_binder",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -515,6 +534,7 @@
     name: "FrameworksCoreTests_internal_os_kernel",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -531,6 +551,7 @@
     name: "FrameworksCoreTests_server_power",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -541,6 +562,7 @@
     name: "FrameworksCoreTests_internal_security",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -552,6 +574,7 @@
     name: "FrameworksCoreTests_internal_util_latency_tracker",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -562,6 +585,7 @@
     name: "FrameworksCoreTests_content_capture_options",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -572,6 +596,7 @@
     name: "FrameworksCoreTests_android_content_integrity",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -582,6 +607,7 @@
     name: "FrameworksCoreTests_android_content_pm_PreSubmit",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -593,6 +619,7 @@
     name: "FrameworksCoreTests_android_content_pm_PostSubmit",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -604,6 +631,7 @@
     name: "FrameworksCoreTests_android_content_res",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -620,6 +648,7 @@
     name: "FrameworksCoreTests_android_content_res_PostSubmit",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -631,6 +660,7 @@
     name: "FrameworksCoreTests_android_service",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -650,6 +680,7 @@
     name: "FrameworksCoreTests_android_view_contentcapture",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -660,6 +691,7 @@
     name: "FrameworksCoreTests_android_view_contentprotection",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -670,6 +702,7 @@
     name: "FrameworksCoreTests_com_android_internal_content_Presubmit",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -681,6 +714,7 @@
     name: "FrameworksCoreTests_drawable",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -691,6 +725,7 @@
     name: "FrameworksCoreTests_accessibility",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -705,6 +740,7 @@
     name: "FrameworksCoreTests_usage",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -715,6 +751,7 @@
     name: "FrameworksCoreTests_fastdata",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -725,6 +762,7 @@
     name: "FrameworksCoreTests_hardware_input",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -735,6 +773,7 @@
     name: "FrameworksCoreTests_view_verified",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -745,9 +784,34 @@
 }
 
 test_module_config {
+    name: "FrameworksCoreTests_android_net_Presubmit",
+    base: "FrameworksCoreTests",
+    test_suites: [
+        "automotive-tests",
+        "device-platinum-tests",
+        "device-tests",
+    ],
+    include_filters: ["android.net"],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
+
+test_module_config {
+    name: "FrameworksCoreTests_content_pm_Postsubmit",
+    base: "FrameworksCoreTests",
+    test_suites: [
+        "automotive-tests",
+        "device-platinum-tests",
+        "device-tests",
+    ],
+    include_filters: ["android.content.pm."],
+    include_annotations: ["android.platform.test.annotations.Postsubmit"],
+}
+
+test_module_config {
     name: "FrameworksCoreTests_jank",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
@@ -762,6 +826,7 @@
     name: "FrameworksCoreTests_Platinum",
     base: "FrameworksCoreTests",
     test_suites: [
+        "automotive-tests",
         "device-tests",
         "device-platinum-tests",
     ],
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
similarity index 77%
rename from services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java
rename to core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
index 46b8e3a..32345e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/DesktopModeFlagsUtilTest.java
+++ b/core/tests/coretests/src/android/window/flags/DesktopModeFlagsTest.java
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server.wm.utils;
+package android.window.flags;
 
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.DESKTOP_WINDOWING_MODE;
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_OFF;
-import static com.android.server.wm.utils.DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_ON;
+import static android.window.flags.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
+
 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
 import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS;
 import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION;
@@ -26,16 +25,16 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.ContentResolver;
+import android.content.Context;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-
-import com.android.server.wm.WindowTestRunner;
-import com.android.server.wm.WindowTestsBase;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -45,21 +44,28 @@
 import java.lang.reflect.Field;
 
 /**
- * Test class for [DesktopModeFlagsUtil]
+ * Test class for {@link DesktopModeFlags}
  *
  * Build/Install/Run:
- * atest WmTests:DesktopModeFlagsUtilTest
+ * atest FrameworksCoreTests:DesktopModeFlagsTest
  */
 @SmallTest
 @Presubmit
-@RunWith(WindowTestRunner.class)
-public class DesktopModeFlagsUtilTest extends WindowTestsBase {
+@RunWith(AndroidJUnit4.class)
+public class DesktopModeFlagsTest {
 
     @Rule
     public SetFlagsRule setFlagsRule = new SetFlagsRule();
 
+    private Context mContext;
+
+    private static final int OVERRIDE_OFF_SETTING = 0;
+    private static final int OVERRIDE_ON_SETTING = 1;
+    private static final int OVERRIDE_UNSET_SETTING = -1;
+
     @Before
     public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
         resetCache();
     }
 
@@ -67,7 +73,7 @@
     @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
     @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_devOptionFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
         // In absence of dev options, follow flag
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
     }
@@ -76,7 +82,7 @@
     @Test
     @DisableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     public void isEnabled_devOptionFlagDisabled_overrideOn_featureFlagOff_returnsFalse() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
     }
@@ -84,7 +90,7 @@
     @Test
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     public void isEnabled_overrideUnset_featureFlagOn_returnsTrue() {
-        setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+        setOverride(OVERRIDE_UNSET_SETTING);
 
         // For overridableFlag, for unset overrides, follow flag
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
@@ -94,7 +100,7 @@
     @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_overrideUnset_featureFlagOff_returnsFalse() {
-        setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+        setOverride(OVERRIDE_UNSET_SETTING);
 
         // For overridableFlag, for unset overrides, follow flag
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
@@ -141,7 +147,7 @@
     @Test
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     public void isEnabled_overrideOff_featureFlagOn_returnsFalse() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // For overridableFlag, follow override if they exist
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
@@ -151,7 +157,7 @@
     @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_overrideOn_featureFlagOff_returnsTrue() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // For overridableFlag, follow override if they exist
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
@@ -160,12 +166,12 @@
     @Test
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     public void isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // For overridableFlag, follow override if they exist
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
 
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // Keep overrides constant through the process
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse();
@@ -175,12 +181,12 @@
     @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // For overridableFlag, follow override if they exist
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
 
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // Keep overrides constant through the process
         assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue();
@@ -190,19 +196,19 @@
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
             FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS})
     public void isEnabled_dwFlagOn_overrideUnset_featureFlagOn_returnsTrue() {
-        setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+        setOverride(OVERRIDE_UNSET_SETTING);
 
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
     }
 
     @Test
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     @DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
     public void isEnabled_dwFlagOn_overrideUnset_featureFlagOff_returnsFalse() {
-        setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+        setOverride(OVERRIDE_UNSET_SETTING);
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
     }
 
     @Test
@@ -212,20 +218,20 @@
             FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
     })
     public void isEnabled_dwFlagOn_overrideOn_featureFlagOn_returnsTrue() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
     }
 
     @Test
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     @DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
     public void isEnabled_dwFlagOn_overrideOn_featureFlagOff_returnsFalse() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
     }
 
     @Test
@@ -235,20 +241,20 @@
             FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
     })
     public void isEnabled_dwFlagOn_overrideOff_featureFlagOn_returnsTrue() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
     }
 
     @Test
     @EnableFlags({FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE})
     @DisableFlags(FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
     public void isEnabled_dwFlagOn_overrideOff_featureFlagOff_returnsFalse() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
     }
 
     @Test
@@ -258,10 +264,10 @@
     })
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_dwFlagOff_overrideUnset_featureFlagOn_returnsTrue() {
-        setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+        setOverride(OVERRIDE_UNSET_SETTING);
 
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
     }
 
     @Test
@@ -271,10 +277,10 @@
             FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
     })
     public void isEnabled_dwFlagOff_overrideUnset_featureFlagOff_returnsFalse() {
-        setOverride(DesktopModeFlagsUtil.ToggleOverride.OVERRIDE_UNSET.getSetting());
+        setOverride(OVERRIDE_UNSET_SETTING);
 
         // For unset overrides, follow flag
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
     }
 
     @Test
@@ -284,10 +290,10 @@
     })
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_dwFlagOff_overrideOn_featureFlagOn_returnsTrue() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
     }
 
     @Test
@@ -297,10 +303,10 @@
             FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
     })
     public void isEnabled_dwFlagOff_overrideOn_featureFlagOff_returnFalse() {
-        setOverride(OVERRIDE_ON.getSetting());
+        setOverride(OVERRIDE_ON_SETTING);
 
         // Follow override if they exist, and is not equal to default toggle state (dw flag)
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
     }
 
     @Test
@@ -310,10 +316,10 @@
     })
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     public void isEnabled_dwFlagOff_overrideOff_featureFlagOn_returnsTrue() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isTrue();
     }
 
     @Test
@@ -323,10 +329,10 @@
             FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS
     })
     public void isEnabled_dwFlagOff_overrideOff_featureFlagOff_returnsFalse() {
-        setOverride(OVERRIDE_OFF.getSetting());
+        setOverride(OVERRIDE_OFF_SETTING);
 
         // When toggle override matches its default state (dw flag), don't override flags
-        assertThat(DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
+        assertThat(DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(mContext)).isFalse();
     }
 
     private void setOverride(Integer setting) {
@@ -341,7 +347,7 @@
     }
 
     private void resetCache() throws Exception {
-        Field cachedToggleOverride = DesktopModeFlagsUtil.class.getDeclaredField(
+        Field cachedToggleOverride = DesktopModeFlags.class.getDeclaredField(
                 "sCachedToggleOverride");
         cachedToggleOverride.setAccessible(true);
         cachedToggleOverride.set(null, null);
diff --git a/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java b/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java
deleted file mode 100644
index a2ff9d7..0000000
--- a/core/tests/vibrator/src/android/os/vibrator/VibrationConfigTest.java
+++ /dev/null
@@ -1,100 +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 android.os.vibrator;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-
-import com.android.internal.R;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class VibrationConfigTest {
-
-    @Rule
-    public MockitoRule rule = MockitoJUnit.rule();
-
-    @Mock
-    private Resources mResourcesMock;
-
-    private final Map<String, String> mSystemProperties = new HashMap<>();
-
-    @Test
-    public void getDefaultVibrationAmplitude_returnsConfiguredAmplitude() {
-        when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(1);
-        assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(1);
-
-        when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(123);
-        assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(123);
-
-        when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(255);
-        assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
-    }
-
-    @Test
-    public void getDefaultVibrationAmplitude_invalidValue_returnsMaxAmplitude() {
-        when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(-1);
-        assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
-
-        when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(0);
-        assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
-
-        when(mResourcesMock.getInteger(R.integer.config_defaultVibrationAmplitude)).thenReturn(500);
-        assertThat(createConfig().getDefaultVibrationAmplitude()).isEqualTo(255);
-    }
-
-    @Test
-    public void getDefaultVibrationScaleLevelGain_returnsConfiguredGain() {
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "1.2");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.2f);
-
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "2");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(2f);
-    }
-
-    @Test
-    public void getDefaultVibrationScaleLevelGain_invalidValue_returnsFixedScaleGain() {
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "invalid");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "-1");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "0.5");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-
-        mSystemProperties.put(VibrationConfig.SCALE_LEVEL_GAIN_SYSTEM_PROPERTY, "1.0");
-        assertThat(createConfig().getDefaultVibrationScaleLevelGain()).isEqualTo(1.4f);
-    }
-
-    private VibrationConfig createConfig() {
-        return new VibrationConfig(mResourcesMock, mSystemProperties::get);
-    }
-}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
index bc46b70..bd430c0 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/Android.bp
+++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp
@@ -62,3 +62,10 @@
         enabled: false,
     },
 }
+
+test_module_config {
+    name: "WMJetpackUnitTests_Presubmit",
+    base: "WMJetpackUnitTests",
+    test_suites: ["device-tests"],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java
index 133242d..a27caf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhonePipKeepClearAlgorithm.java
@@ -57,6 +57,12 @@
         Rect startingBounds = pipBoundsState.getBounds().isEmpty()
                 ? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
                 : pipBoundsState.getBounds();
+        // If IME is not showing and restore bounds (pre-IME bounds) is not empty, we should set PiP
+        // bounds to the restore bounds.
+        if (!pipBoundsState.isImeShowing() && !pipBoundsState.getRestoreBounds().isEmpty()) {
+            startingBounds.set(pipBoundsState.getRestoreBounds());
+            pipBoundsState.clearRestoreBounds();
+        }
         Rect insets = new Rect();
         pipBoundsAlgorithm.getInsetBounds(insets);
         if (pipBoundsState.isImeShowing()) {
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 140d776..c487f75 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
@@ -86,6 +86,7 @@
     @NonNull private final Rect mExpandedBounds = new Rect();
     @NonNull private final Rect mNormalMovementBounds = new Rect();
     @NonNull private final Rect mExpandedMovementBounds = new Rect();
+    @NonNull private final Rect mRestoreBounds = new Rect();
     @NonNull private final PipDisplayLayoutState mPipDisplayLayoutState;
     private final Point mMaxSize = new Point();
     private final Point mMinSize = new Point();
@@ -404,6 +405,10 @@
     public void setImeVisibility(boolean imeShowing, int imeHeight) {
         mIsImeShowing = imeShowing;
         mImeHeight = imeHeight;
+        // If IME is showing, save the current PiP bounds in case we need to restore it later.
+        if (mIsImeShowing) {
+            mRestoreBounds.set(getBounds());
+        }
     }
 
     /** Returns whether the IME is currently showing. */
@@ -411,6 +416,16 @@
         return mIsImeShowing;
     }
 
+    /** Returns the bounds to restore PiP to (bounds before IME was expanded). */
+    public Rect getRestoreBounds() {
+        return mRestoreBounds;
+    }
+
+    /** Sets mRestoreBounds to (0,0,0,0). */
+    public void clearRestoreBounds() {
+        mRestoreBounds.setEmpty();
+    }
+
     /** Returns the IME height. */
     public int getImeHeight() {
         return mImeHeight;
@@ -521,6 +536,10 @@
     /** Set whether the user has resized the PIP. */
     public void setHasUserResizedPip(boolean hasUserResizedPip) {
         mHasUserResizedPip = hasUserResizedPip;
+        // If user resized PiP while IME is showing, clear the pre-IME restore bounds.
+        if (hasUserResizedPip && isImeShowing()) {
+            clearRestoreBounds();
+        }
     }
 
     /** Returns whether the user has moved the PIP. */
@@ -531,6 +550,10 @@
     /** Set whether the user has moved the PIP. */
     public void setHasUserMovedPip(boolean hasUserMovedPip) {
         mHasUserMovedPip = hasUserMovedPip;
+        // If user moved PiP while IME is showing, clear the pre-IME restore bounds.
+        if (hasUserMovedPip && isImeShowing()) {
+            clearRestoreBounds();
+        }
     }
 
     /**
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 7054c17c..8c7dcf2 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
@@ -18,6 +18,7 @@
 
 import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.content.Context;
@@ -114,6 +115,8 @@
 import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
+import com.android.wm.shell.windowdecor.viewhost.DefaultWindowDecorViewHostSupplier;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 import dagger.Binds;
 import dagger.Lazy;
@@ -244,7 +247,8 @@
             AssistContentRequester assistContentRequester,
             MultiInstanceHelper multiInstanceHelper,
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
-            Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler) {
+            Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             return new DesktopModeWindowDecorViewModel(
                     context,
@@ -268,7 +272,8 @@
                     assistContentRequester,
                     multiInstanceHelper,
                     desktopTasksLimiter,
-                    desktopActivityOrientationHandler);
+                    desktopActivityOrientationHandler,
+                    windowDecorViewHostSupplier);
         }
         return new CaptionWindowDecorViewModel(
                 context,
@@ -282,7 +287,8 @@
                 displayController,
                 rootTaskDisplayAreaOrganizer,
                 syncQueue,
-                transitions);
+                transitions,
+                windowDecorViewHostSupplier);
     }
 
     @WMSingleton
@@ -371,6 +377,13 @@
                 context, shellInit, transitions, windowDecorViewModel);
     }
 
+    @WMSingleton
+    @Provides
+    static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier(
+            @ShellMainThread @NonNull CoroutineScope mainScope) {
+        return new DefaultWindowDecorViewHostSupplier(mainScope);
+    }
+
     //
     // One handed mode
     //
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 1b143eb..4ba84ee 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
@@ -34,7 +34,6 @@
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
-import static com.android.wm.shell.Flags.enableFlexibleSplit;
 import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
 import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
@@ -1668,7 +1667,6 @@
         if (mRootTaskInfo == null || mRootTaskInfo.taskId != taskInfo.taskId) {
             throw new IllegalArgumentException(this + "\n Unknown task info changed: " + taskInfo);
         }
-        mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo));
         mRootTaskInfo = taskInfo;
         if (mSplitLayout != null
                 && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
@@ -2822,6 +2820,10 @@
                 mSplitLayout.flingDividerToCenter(this::notifySplitAnimationFinished);
             }
             callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
+            mWindowDecorViewModel.ifPresent(viewModel -> {
+                viewModel.onTaskInfoChanged(finalMainChild.getTaskInfo());
+                viewModel.onTaskInfoChanged(finalSideChild.getTaskInfo());
+            });
             mPausingTasks.clear();
         });
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 11976ae..0151395 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -62,6 +62,7 @@
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 /**
  * View model for the window decoration with a caption and shadows. Works with
@@ -83,6 +84,7 @@
     private final Transitions mTransitions;
     private final Region mExclusionRegion = Region.obtain();
     private final InputManager mInputManager;
+    private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
     private TaskOperations mTaskOperations;
 
     /**
@@ -120,7 +122,8 @@
             DisplayController displayController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             SyncTransactionQueue syncQueue,
-            Transitions transitions) {
+            Transitions transitions,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
         mContext = context;
         mMainExecutor = shellExecutor;
         mMainHandler = mainHandler;
@@ -132,6 +135,7 @@
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
+        mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
         if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
             mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
         }
@@ -295,7 +299,8 @@
                         mMainHandler,
                         mBgExecutor,
                         mMainChoreographer,
-                        mSyncQueue);
+                        mSyncQueue,
+                        mWindowDecorViewHostSupplier);
         mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
 
         final FluidResizeTaskPositioner taskPositioner =
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 349ee0b..46fe68f 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
@@ -56,6 +56,7 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
 import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 /**
  * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -88,8 +89,10 @@
             Handler handler,
             @ShellBackgroundThread ShellExecutor bgExecutor,
             Choreographer choreographer,
-            SyncTransactionQueue syncQueue) {
-        super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface);
+            SyncTransactionQueue syncQueue,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
+        super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
+                windowDecorViewHostSupplier);
         mHandler = handler;
         mBgExecutor = bgExecutor;
         mChoreographer = choreographer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 0f8bd28..7692bd7 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
@@ -41,6 +41,7 @@
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 
 import android.annotation.NonNull;
@@ -122,6 +123,7 @@
 import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
 import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
 import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 import kotlin.Unit;
 
@@ -155,6 +157,7 @@
     private final InteractionJankMonitor mInteractionJankMonitor;
     private final MultiInstanceHelper mMultiInstanceHelper;
     private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
+    private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
     private boolean mTransitionDragActive;
 
     private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
@@ -223,8 +226,8 @@
             AssistContentRequester assistContentRequester,
             MultiInstanceHelper multiInstanceHelper,
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
-            Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler
-    ) {
+            Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
         this(
                 context,
                 shellExecutor,
@@ -244,6 +247,7 @@
                 genericLinksParser,
                 assistContentRequester,
                 multiInstanceHelper,
+                windowDecorViewHostSupplier,
                 new DesktopModeWindowDecoration.Factory(),
                 new InputMonitorFactory(),
                 SurfaceControl.Transaction::new,
@@ -275,6 +279,7 @@
             AppToWebGenericLinksParser genericLinksParser,
             AssistContentRequester assistContentRequester,
             MultiInstanceHelper multiInstanceHelper,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier,
             DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
             InputMonitorFactory inputMonitorFactory,
             Supplier<SurfaceControl.Transaction> transactionFactory,
@@ -300,6 +305,7 @@
         mMultiInstanceHelper = multiInstanceHelper;
         mShellCommandHandler = shellCommandHandler;
         mWindowManager = windowManager;
+        mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
         mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
         mInputMonitorFactory = inputMonitorFactory;
         mTransactionFactory = transactionFactory;
@@ -1098,8 +1104,22 @@
                         // If we are entering split select, handle will no longer be visible and
                         // should not be receiving any input.
                         if (resultType == TO_SPLIT_LEFT_INDICATOR
-                                || resultType != TO_SPLIT_RIGHT_INDICATOR) {
+                                || resultType == TO_SPLIT_RIGHT_INDICATOR) {
                             relevantDecor.disposeStatusBarInputLayer();
+                            // We should also dispose the other split task's input layer if
+                            // applicable.
+                            final int splitPosition = mSplitScreenController
+                                    .getSplitPosition(relevantDecor.mTaskInfo.taskId);
+                            if (splitPosition != SPLIT_POSITION_UNDEFINED) {
+                                final int oppositePosition =
+                                        splitPosition == SPLIT_POSITION_TOP_OR_LEFT
+                                                ? SPLIT_POSITION_BOTTOM_OR_RIGHT
+                                                : SPLIT_POSITION_TOP_OR_LEFT;
+                                final RunningTaskInfo oppositeTaskInfo =
+                                        mSplitScreenController.getTaskInfo(oppositePosition);
+                                mWindowDecorByTaskId.get(oppositeTaskInfo.taskId)
+                                        .disposeStatusBarInputLayer();
+                            }
                         }
                         mMoveToDesktopAnimator = null;
                         return;
@@ -1284,7 +1304,8 @@
                         mRootTaskDisplayAreaOrganizer,
                         mGenericLinksParser,
                         mAssistContentRequester,
-                        mMultiInstanceHelper);
+                        mMultiInstanceHelper,
+                        mWindowDecorViewHostSupplier);
         mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
 
         final TaskPositioner taskPositioner = mTaskPositionerFactory.create(
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 142be91..1409d30 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
@@ -35,7 +35,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.WindowConfiguration.WindowingMode;
 import android.app.assist.AssistContent;
@@ -92,6 +91,7 @@
 import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder;
 import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
 import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 import kotlin.Unit;
 import kotlin.jvm.functions.Function0;
@@ -134,12 +134,9 @@
     private DragPositioningCallback mDragPositioningCallback;
     private DragResizeInputListener mDragResizeListener;
     private DragDetector mDragDetector;
-    private Runnable mCurrentViewHostRunnable = null;
     private RelayoutParams mRelayoutParams = new RelayoutParams();
     private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
             new WindowDecoration.RelayoutResult<>();
-    private final Runnable mViewHostRunnable =
-            () -> updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mResult);
 
     private final Point mPositionInParent = new Point();
     private HandleMenu mHandleMenu;
@@ -190,14 +187,16 @@
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             AppToWebGenericLinksParser genericLinksParser,
             AssistContentRequester assistContentRequester,
-            MultiInstanceHelper multiInstanceHelper) {
+            MultiInstanceHelper multiInstanceHelper,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
         this (context, userContext, displayController, splitScreenController, taskOrganizer,
                 taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue,
                 rootTaskDisplayAreaOrganizer, genericLinksParser, assistContentRequester,
                 SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
                 WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(
                         context.getSystemService(WindowManager.class)),
-                new SurfaceControlViewHostFactory() {}, DefaultMaximizeMenuFactory.INSTANCE,
+                new SurfaceControlViewHostFactory() {}, windowDecorViewHostSupplier,
+                DefaultMaximizeMenuFactory.INSTANCE,
                 DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper);
     }
 
@@ -222,13 +221,14 @@
             Supplier<SurfaceControl> surfaceControlSupplier,
             WindowManagerWrapper windowManagerWrapper,
             SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+            WindowDecorViewHostSupplier windowDecorViewHostSupplier,
             MaximizeMenuFactory maximizeMenuFactory,
             HandleMenuFactory handleMenuFactory,
             MultiInstanceHelper multiInstanceHelper) {
         super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
                 surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
                 windowContainerTransactionSupplier, surfaceControlSupplier,
-                surfaceControlViewHostFactory);
+                surfaceControlViewHostFactory, windowDecorViewHostSupplier);
         mSplitScreenController = splitScreenController;
         mHandler = handler;
         mBgExecutor = bgExecutor;
@@ -337,73 +337,6 @@
             SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
             boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
         Trace.beginSection("DesktopModeWindowDecoration#relayout");
-        if (taskInfo.isFreeform()) {
-            // The Task is in Freeform mode -> show its header in sync since it's an integral part
-            // of the window itself - a delayed header might cause bad UX.
-            relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw,
-                    shouldSetTaskPositionAndCrop);
-        } else {
-            // The Task is outside Freeform mode -> allow the handle view to be delayed since the
-            // handle is just a small addition to the window.
-            relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw,
-                    shouldSetTaskPositionAndCrop);
-        }
-        Trace.endSection();
-    }
-
-    /** Run the whole relayout phase immediately without delay. */
-    private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo,
-            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
-        // Clear the current ViewHost runnable as we will update the ViewHost here
-        clearCurrentViewHostRunnable();
-        updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw,
-                shouldSetTaskPositionAndCrop);
-        if (mResult.mRootView != null) {
-            updateViewHost(mRelayoutParams, startT, mResult);
-        }
-    }
-
-    /**
-     * Clear the current ViewHost runnable - to ensure it doesn't run once relayout params have been
-     * updated.
-     */
-    private void clearCurrentViewHostRunnable() {
-        if (mCurrentViewHostRunnable != null) {
-            mHandler.removeCallbacks(mCurrentViewHostRunnable);
-            mCurrentViewHostRunnable = null;
-        }
-    }
-
-    /**
-     * Relayout the window decoration but repost some of the work, to unblock the current callstack.
-     */
-    private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo,
-            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
-        if (applyStartTransactionOnDraw) {
-            throw new IllegalArgumentException(
-                    "We cannot both sync viewhost ondraw and delay viewhost creation.");
-        }
-        // Clear the current ViewHost runnable as we will update the ViewHost here
-        clearCurrentViewHostRunnable();
-        updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT,
-                false /* applyStartTransactionOnDraw */, shouldSetTaskPositionAndCrop);
-        if (mResult.mRootView == null) {
-            // This means something blocks the window decor from showing, e.g. the task is hidden.
-            // Nothing is set up in this case including the decoration surface.
-            return;
-        }
-        // Store the current runnable so it can be removed if we start a new relayout.
-        mCurrentViewHostRunnable = mViewHostRunnable;
-        mHandler.post(mCurrentViewHostRunnable);
-    }
-
-    @SuppressLint("MissingPermission")
-    private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo,
-            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            boolean applyStartTransactionOnDraw, boolean shouldSetTaskPositionAndCrop) {
-        Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces");
 
         if (Flags.enableDesktopWindowingAppToWeb()) {
             setCapturedLink(taskInfo.capturedLink, taskInfo.capturedLinkTimestamp);
@@ -420,8 +353,8 @@
         final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
         final WindowContainerTransaction wct = new WindowContainerTransaction();
 
-        Trace.beginSection("DesktopModeWindowDecoration#relayout-updateViewsAndSurfaces");
-        updateViewsAndSurfaces(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
+        Trace.beginSection("DesktopModeWindowDecoration#relayout-inner");
+        relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
         Trace.endSection();
         // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
 
@@ -433,7 +366,7 @@
             // This means something blocks the window decor from showing, e.g. the task is hidden.
             // Nothing is set up in this case including the decoration surface.
             disposeStatusBarInputLayer();
-            Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces
+            Trace.endSection(); // DesktopModeWindowDecoration#relayout
             return;
         }
 
@@ -441,12 +374,12 @@
             disposeStatusBarInputLayer();
             mWindowDecorViewHolder = createViewHolder();
         }
-        Trace.beginSection("DesktopModeWindowDecoration#relayout-binding");
 
         final Point position = new Point();
         if (isAppHandle(mWindowDecorViewHolder)) {
             position.set(determineHandlePosition());
         }
+        Trace.beginSection("DesktopModeWindowDecoration#relayout-bindData");
         mWindowDecorViewHolder.bindData(mTaskInfo,
                 position,
                 mResult.mCaptionWidth,
@@ -460,7 +393,7 @@
         }
         updateDragResizeListener(oldDecorationSurface);
         updateMaximizeMenu(startT);
-        Trace.endSection(); // DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces
+        Trace.endSection(); // DesktopModeWindowDecoration#relayout
     }
 
     private boolean isCaptionVisible() {
@@ -638,6 +571,10 @@
         relayoutParams.mLayoutResId = captionLayoutId;
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
         relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
+        // Allow the handle view to be delayed since the handle is just a small addition to the
+        // window, whereas the header cannot be delayed because it is expected to be visible from
+        // the first frame.
+        relayoutParams.mAsyncViewHost = isAppHandle;
 
         if (isAppHeader) {
             if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
@@ -1253,7 +1190,6 @@
         mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
         disposeResizeVeil();
         disposeStatusBarInputLayer();
-        clearCurrentViewHostRunnable();
         super.close();
     }
 
@@ -1364,7 +1300,8 @@
                 RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
                 AppToWebGenericLinksParser genericLinksParser,
                 AssistContentRequester assistContentRequester,
-                MultiInstanceHelper multiInstanceHelper) {
+                MultiInstanceHelper multiInstanceHelper,
+                WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
             return new DesktopModeWindowDecoration(
                     context,
                     userContext,
@@ -1380,7 +1317,8 @@
                     rootTaskDisplayAreaOrganizer,
                     genericLinksParser,
                     assistContentRequester,
-                    multiInstanceHelper);
+                    multiInstanceHelper,
+                    windowDecorViewHostSupplier);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
new file mode 100644
index 0000000..e8131a0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+import android.graphics.PointF
+import android.graphics.Rect
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CtrlType
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * [AbstractTaskPositionerDecorator] implementation for validating the coordinates associated with a
+ * drag action, to maintain a fixed aspect ratio before being used by the task positioner.
+ */
+class FixedAspectRatioTaskPositionerDecorator (
+    private val windowDecoration: DesktopModeWindowDecoration,
+    decoratedTaskPositioner: TaskPositioner
+) : AbstractTaskPositionerDecorator(decoratedTaskPositioner) {
+
+    private var originalCtrlType = CTRL_TYPE_UNDEFINED
+    private var edgeResizeCtrlType = CTRL_TYPE_UNDEFINED
+    private val lastRepositionedBounds = Rect()
+    private val startingPoint = PointF()
+    private val lastValidPoint = PointF()
+    private var startingAspectRatio = 0f
+    private var isTaskPortrait = false
+
+    override fun onDragPositioningStart(@CtrlType ctrlType: Int, x: Float, y: Float): Rect {
+        originalCtrlType = ctrlType
+        if (!requiresFixedAspectRatio()) {
+            return super.onDragPositioningStart(originalCtrlType, x, y)
+        }
+
+        lastRepositionedBounds.set(
+            windowDecoration.mTaskInfo.configuration.windowConfiguration.bounds)
+        startingPoint.set(x, y)
+        lastValidPoint.set(x, y)
+        val startingBoundWidth = lastRepositionedBounds.width()
+        val startingBoundHeight = lastRepositionedBounds.height()
+        startingAspectRatio = max(startingBoundWidth, startingBoundHeight).toFloat() /
+                min(startingBoundWidth, startingBoundHeight).toFloat()
+        isTaskPortrait = startingBoundWidth <= startingBoundHeight
+
+        lastRepositionedBounds.set(
+            when (originalCtrlType) {
+                // If resize in an edge resize, adjust ctrlType passed to onDragPositioningStart() to
+                // mimic a corner resize instead. As at lest two adjacent edges need to be resized
+                // in relation to each other to maintain the apps aspect ratio. The additional adjacent
+                // edge is selected based on its proximity (closest) to the start of the drag.
+                CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> {
+                    val verticalMidPoint = lastRepositionedBounds.top + (startingBoundHeight / 2)
+                    edgeResizeCtrlType = originalCtrlType +
+                            if (y < verticalMidPoint) CTRL_TYPE_TOP else CTRL_TYPE_BOTTOM
+                    super.onDragPositioningStart(edgeResizeCtrlType, x, y)
+                }
+                CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> {
+                    val horizontalMidPoint = lastRepositionedBounds.left + (startingBoundWidth / 2)
+                    edgeResizeCtrlType = originalCtrlType +
+                            if (x < horizontalMidPoint) CTRL_TYPE_LEFT else CTRL_TYPE_RIGHT
+                    super.onDragPositioningStart(edgeResizeCtrlType, x, y)
+                }
+                // If resize is corner resize, no alteration to the ctrlType needs to be made.
+                else -> {
+                    edgeResizeCtrlType = CTRL_TYPE_UNDEFINED
+                    super.onDragPositioningStart(originalCtrlType, x, y)
+                }
+            }
+        )
+        return lastRepositionedBounds
+    }
+
+    override fun onDragPositioningMove(x: Float, y: Float): Rect {
+        if (!requiresFixedAspectRatio()) {
+            return super.onDragPositioningMove(x, y)
+        }
+
+        val diffX = x - lastValidPoint.x
+        val diffY = y - lastValidPoint.y
+        when (originalCtrlType) {
+            CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, CTRL_TYPE_TOP + CTRL_TYPE_LEFT -> {
+                if ((diffX > 0 && diffY > 0) || (diffX < 0 && diffY < 0)) {
+                    // Drag coordinate falls within valid region (90 - 180 degrees or 270- 360
+                    // degrees from the corner the previous valid point). Allow resize with adjusted
+                    // coordinates to maintain aspect ratio.
+                    lastRepositionedBounds.set(dragAdjustedMove(x, y))
+                }
+            }
+            CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> {
+                if ((diffX > 0 && diffY < 0) || (diffX < 0 && diffY > 0)) {
+                    // Drag coordinate falls within valid region (180 - 270 degrees or 0 - 90
+                    // degrees from the corner the previous valid point). Allow resize with adjusted
+                    // coordinates to maintain aspect ratio.
+                    lastRepositionedBounds.set(dragAdjustedMove(x, y))
+                }
+            }
+            CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> {
+                // If resize is on left or right edge, always adjust the y coordinate.
+                val adjustedY = getScaledChangeForY(x)
+                lastValidPoint.set(x, adjustedY)
+                lastRepositionedBounds.set(super.onDragPositioningMove(x, adjustedY))
+            }
+            CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> {
+                // If resize is on top or bottom edge, always adjust the x coordinate.
+                val adjustedX = getScaledChangeForX(y)
+                lastValidPoint.set(adjustedX, y)
+                lastRepositionedBounds.set(super.onDragPositioningMove(adjustedX, y))
+            }
+        }
+        return lastRepositionedBounds
+    }
+
+    override fun onDragPositioningEnd(x: Float, y: Float): Rect {
+        if (!requiresFixedAspectRatio()) {
+            return super.onDragPositioningEnd(x, y)
+        }
+
+        val diffX = x - lastValidPoint.x
+        val diffY = y - lastValidPoint.y
+
+        when (originalCtrlType) {
+            CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, CTRL_TYPE_TOP + CTRL_TYPE_LEFT -> {
+                if ((diffX > 0 && diffY > 0) || (diffX < 0 && diffY < 0)) {
+                    // Drag coordinate falls within valid region (90 - 180 degrees or 270- 360
+                    // degrees from the corner the previous valid point). End resize with adjusted
+                    // coordinates to maintain aspect ratio.
+                    return dragAdjustedEnd(x, y)
+                }
+                // If end of resize is not within valid region, end resize from last valid
+                // coordinates.
+                return super.onDragPositioningEnd(lastValidPoint.x, lastValidPoint.y)
+            }
+            CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> {
+                if ((diffX > 0 && diffY < 0) || (diffX < 0 && diffY > 0)) {
+                    // Drag coordinate falls within valid region (180 - 260 degrees or 0 - 90
+                    // degrees from the corner the previous valid point). End resize with adjusted
+                    // coordinates to maintain aspect ratio.
+                    return dragAdjustedEnd(x, y)
+                }
+                // If end of resize is not within valid region, end resize from last valid
+                // coordinates.
+                return super.onDragPositioningEnd(lastValidPoint.x, lastValidPoint.y)
+            }
+            CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT -> {
+                // If resize is on left or right edge, always adjust the y coordinate.
+                return super.onDragPositioningEnd(x, getScaledChangeForY(x))
+            }
+            CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM -> {
+                // If resize is on top or bottom edge, always adjust the x coordinate.
+                return super.onDragPositioningEnd(getScaledChangeForX(y), y)
+            }
+            else -> {
+                return super.onDragPositioningEnd(x, y)
+            }
+        }
+    }
+
+    private fun dragAdjustedMove(x: Float, y: Float): Rect {
+        val absDiffX = abs(x - lastValidPoint.x)
+        val absDiffY = abs(y - lastValidPoint.y)
+        if (absDiffY < absDiffX) {
+            lastValidPoint.set(getScaledChangeForX(y), y)
+            return super.onDragPositioningMove(getScaledChangeForX(y), y)
+        }
+        lastValidPoint.set(x, getScaledChangeForY(x))
+        return super.onDragPositioningMove(x, getScaledChangeForY(x))
+    }
+
+    private fun dragAdjustedEnd(x: Float, y: Float): Rect {
+        val absDiffX = abs(x - lastValidPoint.x)
+        val absDiffY = abs(y - lastValidPoint.y)
+        if (absDiffY < absDiffX) {
+            return super.onDragPositioningEnd(getScaledChangeForX(y), y)
+        }
+        return super.onDragPositioningEnd(x, getScaledChangeForY(x))
+    }
+
+    /**
+     * Calculate the required change in the y dimension, given the change in the x dimension, to
+     * maintain the applications starting aspect ratio when resizing to a given x coordinate.
+     */
+    private fun getScaledChangeForY(x: Float): Float {
+        val changeXDimension = x - startingPoint.x
+        val changeYDimension = if (isTaskPortrait) {
+            changeXDimension * startingAspectRatio
+        } else {
+            changeXDimension / startingAspectRatio
+        }
+        if (originalCtrlType.isBottomRightOrTopLeftCorner()
+            || edgeResizeCtrlType.isBottomRightOrTopLeftCorner()) {
+            return startingPoint.y + changeYDimension
+        }
+        return startingPoint.y - changeYDimension
+    }
+
+    /**
+     * Calculate the required change in the x dimension, given the change in the y dimension, to
+     * maintain the applications starting aspect ratio when resizing to a given y coordinate.
+     */
+    private fun getScaledChangeForX(y: Float): Float {
+        val changeYDimension = y - startingPoint.y
+        val changeXDimension = if (isTaskPortrait) {
+            changeYDimension / startingAspectRatio
+        } else {
+            changeYDimension * startingAspectRatio
+        }
+        if (originalCtrlType.isBottomRightOrTopLeftCorner()
+            || edgeResizeCtrlType.isBottomRightOrTopLeftCorner()) {
+            return startingPoint.x + changeXDimension
+        }
+        return startingPoint.x - changeXDimension
+    }
+
+    /**
+     * If the action being triggered originated from the bottom right or top left corner of the
+     * window.
+     */
+    private fun @receiver:CtrlType Int.isBottomRightOrTopLeftCorner(): Boolean {
+        return this == CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT || this == CTRL_TYPE_TOP + CTRL_TYPE_LEFT
+    }
+
+    /**
+     * If the action being triggered is a resize action.
+     */
+    private fun @receiver:CtrlType Int.isResizing(): Boolean {
+        return (this and CTRL_TYPE_TOP) != 0 || (this and CTRL_TYPE_BOTTOM) != 0
+                || (this and CTRL_TYPE_LEFT) != 0 || (this and CTRL_TYPE_RIGHT) != 0
+    }
+
+    /**
+     * Whether the aspect ratio of the activity needs to be maintained during the current drag
+     * action. If the current action is not a resize (there is no bounds change) so the aspect ratio
+     * is already maintained and does not need handling here. If the activity is resizeable, it
+     * can handle aspect ratio changes itself so again we do not need to handle it here.
+     */
+    private fun requiresFixedAspectRatio(): Boolean {
+        return originalCtrlType.isResizing() && !windowDecoration.mTaskInfo.isResizeable
+    }
+}
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 4af5b2c..3694845 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
@@ -62,6 +62,8 @@
 import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer;
 import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -116,6 +118,7 @@
     final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
     final Supplier<WindowContainerTransaction> mWindowContainerTransactionSupplier;
     final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
+    @NonNull private final WindowDecorViewHostSupplier mWindowDecorViewHostSupplier;
     private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
             new DisplayController.OnDisplaysChangedListener() {
                 @Override
@@ -137,9 +140,7 @@
     Context mDecorWindowContext;
     SurfaceControl mDecorationContainerSurface;
 
-    SurfaceControl mCaptionContainerSurface;
-    private WindowlessWindowManager mCaptionWindowManager;
-    private SurfaceControlViewHost mViewHost;
+    private WindowDecorViewHost mDecorViewHost;
     private Configuration mWindowDecorConfig;
     TaskDragResizer mTaskDragResizer;
     boolean mIsCaptionVisible;
@@ -158,11 +159,13 @@
             DisplayController displayController,
             ShellTaskOrganizer taskOrganizer,
             RunningTaskInfo taskInfo,
-            SurfaceControl taskSurface) {
+            SurfaceControl taskSurface,
+            @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
         this(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
                 SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
                 WindowContainerTransaction::new, SurfaceControl::new,
-                new SurfaceControlViewHostFactory() {});
+                new SurfaceControlViewHostFactory() {},
+                windowDecorViewHostSupplier);
     }
 
     WindowDecoration(
@@ -176,7 +179,8 @@
             Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
             Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
             Supplier<SurfaceControl> surfaceControlSupplier,
-            SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
+            SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+            @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
         mContext = context;
         mUserContext = userContext;
         mDisplayController = displayController;
@@ -187,6 +191,7 @@
         mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
         mWindowContainerTransactionSupplier = windowContainerTransactionSupplier;
         mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
+        mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
         mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
         final InsetsState insetsState = mDisplayController.getInsetsState(mTaskInfo.displayId);
         mIsStatusBarVisible = insetsState != null
@@ -212,15 +217,7 @@
     void relayout(RelayoutParams params, SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView,
             RelayoutResult<T> outResult) {
-        updateViewsAndSurfaces(params, startT, finishT, wct, rootView, outResult);
-        if (outResult.mRootView != null) {
-            updateViewHost(params, startT, outResult);
-        }
-    }
-
-    protected void updateViewsAndSurfaces(RelayoutParams params,
-            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
-            WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) {
+        Trace.beginSection("WindowDecoration#relayout");
         outResult.reset();
         if (params.mRunningTaskInfo != null) {
             mTaskInfo = params.mRunningTaskInfo;
@@ -231,17 +228,21 @@
         if (!mTaskInfo.isVisible) {
             releaseViews(wct);
             finishT.hide(mTaskSurface);
+            Trace.endSection(); // WindowDecoration#relayout
             return;
         }
-
+        Trace.beginSection("WindowDecoration#relayout-inflateIfNeeded");
         inflateIfNeeded(params, wct, rootView, oldLayoutResId, outResult);
-        if (outResult.mRootView == null) {
-            // Didn't manage to create a root view, early out.
+        Trace.endSection();
+        final boolean hasCaptionView = outResult.mRootView != null;
+        if (!hasCaptionView) {
+            Trace.endSection(); // WindowDecoration#relayout
             return;
         }
-        rootView = null; // Clear it just in case we use it accidentally
 
+        Trace.beginSection("WindowDecoration#relayout-updateCaptionVisibility");
         updateCaptionVisibility(outResult.mRootView);
+        Trace.endSection();
 
         final Rect taskBounds = mTaskInfo.getConfiguration().windowConfiguration.getBounds();
         outResult.mWidth = taskBounds.width();
@@ -254,10 +255,23 @@
                 ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width();
         outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
 
+        Trace.beginSection("WindowDecoration#relayout-acquire");
+        if (mDecorViewHost == null) {
+            mDecorViewHost = mWindowDecorViewHostSupplier.acquire(mDecorWindowContext, mDisplay);
+        }
+        Trace.endSection();
+
+        final SurfaceControl captionSurface = mDecorViewHost.getSurfaceControl();
+        Trace.beginSection("WindowDecoration#relayout-updateSurfacesAndInsets");
         updateDecorationContainerSurface(startT, outResult);
-        updateCaptionContainerSurface(startT, outResult);
+        updateCaptionContainerSurface(captionSurface, startT, outResult);
         updateCaptionInsets(params, wct, outResult, taskBounds);
         updateTaskSurface(params, startT, finishT, outResult);
+        Trace.endSection();
+
+        outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
+        updateViewHierarchy(params, outResult, startT);
+        Trace.endSection(); // WindowDecoration#relayout
     }
 
     private void inflateIfNeeded(RelayoutParams params, WindowContainerTransaction wct,
@@ -305,6 +319,32 @@
         return (T) LayoutInflater.from(context).inflate(layoutResId, null);
     }
 
+    private void updateViewHierarchy(@NonNull RelayoutParams params,
+            @NonNull RelayoutResult<T> outResult, @NonNull SurfaceControl.Transaction startT) {
+        Trace.beginSection("WindowDecoration#updateViewHierarchy");
+        final WindowManager.LayoutParams lp =
+                new WindowManager.LayoutParams(
+                        outResult.mCaptionWidth,
+                        outResult.mCaptionHeight,
+                        TYPE_APPLICATION,
+                        FLAG_NOT_FOCUSABLE | FLAG_SPLIT_TOUCH,
+                        PixelFormat.TRANSPARENT);
+        lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
+        lp.setTrustedOverlay();
+        lp.inputFeatures = params.mInputFeatures;
+        if (params.mAsyncViewHost) {
+            if (params.mApplyStartTransactionOnDraw) {
+                throw new IllegalArgumentException(
+                        "We cannot both sync viewhost ondraw and delay viewhost creation.");
+            }
+            mDecorViewHost.updateViewAsync(outResult.mRootView, lp, mTaskInfo.getConfiguration());
+        } else {
+            mDecorViewHost.updateView(outResult.mRootView, lp, mTaskInfo.getConfiguration(),
+                    params.mApplyStartTransactionOnDraw ? startT : null);
+        }
+        Trace.endSection();
+    }
+
     private void updateDecorationContainerSurface(
             SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
         if (mDecorationContainerSurface == null) {
@@ -325,23 +365,14 @@
                 .show(mDecorationContainerSurface);
     }
 
-    private void updateCaptionContainerSurface(
+    private void updateCaptionContainerSurface(@NonNull SurfaceControl captionSurface,
             SurfaceControl.Transaction startT, RelayoutResult<T> outResult) {
-        if (mCaptionContainerSurface == null) {
-            final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
-            mCaptionContainerSurface = builder
-                    .setName("Caption container of Task=" + mTaskInfo.taskId)
-                    .setContainerLayer()
-                    .setParent(mDecorationContainerSurface)
-                    .setCallsite("WindowDecoration.updateCaptionContainerSurface")
-                    .build();
-        }
-
-        startT.setWindowCrop(mCaptionContainerSurface, outResult.mCaptionWidth,
+        startT.reparent(captionSurface, mDecorationContainerSurface)
+                .setWindowCrop(captionSurface, outResult.mCaptionWidth,
                         outResult.mCaptionHeight)
-                .setPosition(mCaptionContainerSurface, outResult.mCaptionX, 0 /* y */)
-                .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER)
-                .show(mCaptionContainerSurface);
+                .setPosition(captionSurface, outResult.mCaptionX, 0 /* y */)
+                .setLayer(captionSurface, CAPTION_LAYER_Z_ORDER)
+                .show(captionSurface);
     }
 
     private void updateCaptionInsets(RelayoutParams params, WindowContainerTransaction wct,
@@ -435,64 +466,6 @@
         }
     }
 
-    /**
-     * Updates a {@link SurfaceControlViewHost} to connect the window decoration surfaces with our
-     * View hierarchy.
-     *
-     * @param params parameters to use from the last relayout
-     * @param onDrawTransaction a transaction to apply in sync with #onDraw
-     * @param outResult results to use from the last relayout
-     *
-     */
-    protected void updateViewHost(RelayoutParams params,
-            SurfaceControl.Transaction onDrawTransaction, RelayoutResult<T> outResult) {
-        Trace.beginSection("CaptionViewHostLayout");
-        if (mCaptionWindowManager == null) {
-            // Put caption under a container surface because ViewRootImpl sets the destination frame
-            // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
-            mCaptionWindowManager = new WindowlessWindowManager(
-                    mTaskInfo.getConfiguration(), mCaptionContainerSurface,
-                    null /* hostInputToken */);
-        }
-        mCaptionWindowManager.setConfiguration(mTaskInfo.getConfiguration());
-        final WindowManager.LayoutParams lp =
-                new WindowManager.LayoutParams(
-                        outResult.mCaptionWidth,
-                        outResult.mCaptionHeight,
-                        TYPE_APPLICATION,
-                        FLAG_NOT_FOCUSABLE | FLAG_SPLIT_TOUCH,
-                        PixelFormat.TRANSPARENT);
-        lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
-        lp.setTrustedOverlay();
-        lp.inputFeatures = params.mInputFeatures;
-        if (mViewHost == null) {
-            Trace.beginSection("CaptionViewHostLayout-new");
-            mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
-                    mCaptionWindowManager);
-            if (params.mApplyStartTransactionOnDraw) {
-                if (onDrawTransaction == null) {
-                    throw new IllegalArgumentException("Trying to sync a null Transaction");
-                }
-                mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
-            }
-            outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
-            mViewHost.setView(outResult.mRootView, lp);
-            Trace.endSection();
-        } else {
-            Trace.beginSection("CaptionViewHostLayout-relayout");
-            if (params.mApplyStartTransactionOnDraw) {
-                if (onDrawTransaction == null) {
-                    throw new IllegalArgumentException("Trying to sync a null Transaction");
-                }
-                mViewHost.getRootSurfaceControl().applyTransactionOnDraw(onDrawTransaction);
-            }
-            outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
-            mViewHost.relayout(lp);
-            Trace.endSection();
-        }
-        Trace.endSection(); // CaptionViewHostLayout
-    }
-
     private Rect calculateBoundingRect(@NonNull OccludingCaptionElement element,
             int elementWidthPx, @NonNull Rect captionRect) {
         switch (element.mAlignment) {
@@ -530,7 +503,14 @@
      * Checks if task has entered/exited immersive mode and requires a change in caption visibility.
      */
     private void updateCaptionVisibility(View rootView) {
-        mIsCaptionVisible = mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded;
+        // Caption should always be visible in freeform mode. When not in freeform, align with the
+        // status bar except when showing over keyguard (where it should not shown).
+        //  TODO(b/356405803): Investigate how it's possible for the status bar visibility to be
+        //   false while a freeform window is open if the status bar is always forcibly-shown. It
+        //   may be that the InsetsState (from which |mIsStatusBarVisible| is set) still contains
+        //   an invisible insets source in immersive cases even if the status bar is shown?
+        mIsCaptionVisible = mTaskInfo.isFreeform()
+                || (mIsStatusBarVisible && !mIsKeyguardVisibleAndOccluded);
         setCaptionVisibility(rootView, mIsCaptionVisible);
     }
 
@@ -573,18 +553,11 @@
     }
 
     void releaseViews(WindowContainerTransaction wct) {
-        if (mViewHost != null) {
-            mViewHost.release();
-            mViewHost = null;
-        }
-
-        mCaptionWindowManager = null;
-
         final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
         boolean released = false;
-        if (mCaptionContainerSurface != null) {
-            t.remove(mCaptionContainerSurface);
-            mCaptionContainerSurface = null;
+        if (mDecorViewHost != null) {
+            mWindowDecorViewHostSupplier.release(mDecorViewHost, t);
+            mDecorViewHost = null;
             released = true;
         }
 
@@ -735,6 +708,7 @@
 
         boolean mApplyStartTransactionOnDraw;
         boolean mSetTaskPositionAndCrop;
+        boolean mAsyncViewHost;
 
         void reset() {
             mLayoutResId = Resources.ID_NULL;
@@ -751,6 +725,7 @@
 
             mApplyStartTransactionOnDraw = false;
             mSetTaskPositionAndCrop = false;
+            mAsyncViewHost = false;
             mWindowDecorConfig = null;
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
new file mode 100644
index 0000000..139e679
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.viewhost
+
+import android.content.Context
+import android.content.res.Configuration
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import androidx.tracing.Trace
+import com.android.internal.annotations.VisibleForTesting
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+typealias SurfaceControlViewHostFactory =
+            (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
+
+/**
+ * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHost].
+ *
+ * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
+ * any attempts to do will throw, which means that once a [View] is added using [updateView] or
+ * [updateViewAsync], only its properties and binding may be changed, its children views may be
+ * added, removed or changed and its [WindowManager.LayoutParams] may be changed.
+ * It also supports asynchronously updating the view hierarchy using [updateViewAsync], in which
+ * case the update work will be posted on the [ShellMainThread] with no delay.
+ */
+class DefaultWindowDecorViewHost(
+    private val context: Context,
+    @ShellMainThread private val mainScope: CoroutineScope,
+    private val display: Display,
+    private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
+        SurfaceControlViewHost(c, d, wwm, s)
+    }
+) : WindowDecorViewHost {
+
+    private val rootSurface: SurfaceControl = SurfaceControl.Builder()
+            .setName("DefaultWindowDecorViewHost surface")
+            .setContainerLayer()
+            .setCallsite("DefaultWindowDecorViewHost#init")
+            .build()
+
+    private var wwm: WindowlessWindowManager? = null
+    @VisibleForTesting
+    var viewHost: SurfaceControlViewHost? = null
+    private var currentUpdateJob: Job? = null
+
+    override val surfaceControl: SurfaceControl
+        get() = rootSurface
+
+    override fun updateView(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+        onDrawTransaction: SurfaceControl.Transaction?
+    ) {
+        Trace.beginSection("DefaultWindowDecorViewHost#updateView")
+        clearCurrentUpdateJob()
+        updateViewHost(view, attrs, configuration, onDrawTransaction)
+        Trace.endSection()
+    }
+
+    override fun updateViewAsync(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration
+    ) {
+        Trace.beginSection("DefaultWindowDecorViewHost#updateViewAsync")
+        clearCurrentUpdateJob()
+        currentUpdateJob = mainScope.launch {
+            updateViewHost(view, attrs, configuration, onDrawTransaction = null)
+        }
+        Trace.endSection()
+    }
+
+    override fun release(t: SurfaceControl.Transaction) {
+        clearCurrentUpdateJob()
+        viewHost?.release()
+        t.remove(rootSurface)
+    }
+
+    private fun updateViewHost(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+        onDrawTransaction: SurfaceControl.Transaction?
+    ) {
+        Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost")
+        if (wwm == null) {
+            wwm = WindowlessWindowManager(configuration, rootSurface, null)
+        }
+        requireWindowlessWindowManager().setConfiguration(configuration)
+        if (viewHost == null) {
+            viewHost = surfaceControlViewHostFactory.invoke(
+                context,
+                display,
+                requireWindowlessWindowManager(),
+                "DefaultWindowDecorViewHost#updateViewHost"
+            )
+        }
+        onDrawTransaction?.let {
+            requireViewHost().rootSurfaceControl.applyTransactionOnDraw(it)
+        }
+        if (requireViewHost().view == null) {
+            Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-setView")
+            requireViewHost().setView(view, attrs)
+            Trace.endSection()
+        } else {
+            check(requireViewHost().view == view) { "Changing view is not allowed" }
+            Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-relayout")
+            requireViewHost().relayout(attrs)
+            Trace.endSection()
+        }
+        Trace.endSection()
+    }
+
+    private fun clearCurrentUpdateJob() {
+        currentUpdateJob?.cancel()
+        currentUpdateJob = null
+    }
+
+    private fun requireWindowlessWindowManager(): WindowlessWindowManager {
+        return wwm ?: error("Expected non-null windowless window manager")
+    }
+
+    private fun requireViewHost(): SurfaceControlViewHost {
+        return viewHost ?: error("Expected non-null view host")
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..9997e8f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostSupplier.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.view.Display
+import android.view.SurfaceControl
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * A supplier of [DefaultWindowDecorViewHost]s. It creates a new one every time one is requested.
+ */
+class DefaultWindowDecorViewHostSupplier(
+    @ShellMainThread private val mainScope: CoroutineScope,
+) : WindowDecorViewHostSupplier<DefaultWindowDecorViewHost> {
+
+    override fun acquire(context: Context, display: Display): DefaultWindowDecorViewHost {
+        return DefaultWindowDecorViewHost(context, mainScope, display)
+    }
+
+    override fun release(viewHost: DefaultWindowDecorViewHost, t: SurfaceControl.Transaction) {
+        viewHost.release(t)
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.kt
new file mode 100644
index 0000000..3fbaea8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHost.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.wm.shell.windowdecor.viewhost
+
+import android.content.res.Configuration
+import android.view.SurfaceControl
+import android.view.View
+import android.view.WindowManager
+import com.android.wm.shell.windowdecor.WindowDecoration
+
+/**
+ * An interface for a utility that hosts a [WindowDecoration]'s [View] hierarchy under a
+ * [SurfaceControl].
+ */
+interface WindowDecorViewHost {
+    /** The surface where the underlying [View] hierarchy is being rendered. */
+    val surfaceControl: SurfaceControl
+
+    /** Synchronously update the view hierarchy of this view host. */
+    fun updateView(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration,
+        onDrawTransaction: SurfaceControl.Transaction?
+    )
+
+    /** Asynchronously update the view hierarchy of this view host. */
+    fun updateViewAsync(
+        view: View,
+        attrs: WindowManager.LayoutParams,
+        configuration: Configuration
+    )
+
+    /** Releases the underlying [View] hierarchy and removes the backing [SurfaceControl]. */
+    fun release(t: SurfaceControl.Transaction)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..0e23584
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/WindowDecorViewHostSupplier.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.view.Display
+import android.view.SurfaceControl
+
+/**
+ * An interface for a supplier of [WindowDecorViewHost]s.
+ */
+interface WindowDecorViewHostSupplier<T : WindowDecorViewHost> {
+    /** Acquire a [WindowDecorViewHost]. */
+    fun acquire(context: Context, display: Display): T
+
+    /**
+     * Release a [WindowDecorViewHost] when it is no longer used.
+     *
+     * @param viewHost the [WindowDecorViewHost] to release
+     * @param t a transaction that may be used to remove any underlying backing [SurfaceControl]
+     *          that are hosting this [WindowDecorViewHost]. The supplier is not expected to apply
+     *          the transaction. It should be applied by the owner of this supplier.
+     */
+    fun release(viewHost: T, t: SurfaceControl.Transaction)
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
index 8c7b47e..e3798e9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
@@ -109,6 +109,7 @@
         final Rect pipBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(50, 50, 150, 150);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
@@ -127,6 +128,7 @@
         final Rect pipBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(100, 100, 150, 150);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
@@ -145,6 +147,7 @@
         final Rect pipBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(50, 50, 150, 150);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         when(mMockPipBoundsState.isStashed()).thenReturn(true);
         when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
         doAnswer(invocation -> {
@@ -164,6 +167,7 @@
         final Rect pipBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(100, 100, 150, 150);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         when(mMockPipBoundsState.isStashed()).thenReturn(true);
         when(mMockPipBoundsState.getRestrictedKeepClearAreas()).thenReturn(Set.of(keepClearRect));
         doAnswer(invocation -> {
@@ -185,6 +189,7 @@
         final Rect expected = new Rect(
                 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
             arg0.set(DISPLAY_BOUNDS);
@@ -205,6 +210,7 @@
         final Rect expected = new Rect(
                 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
             arg0.set(DISPLAY_BOUNDS);
@@ -227,6 +233,7 @@
                 DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
                 DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
             arg0.set(DISPLAY_BOUNDS);
@@ -249,6 +256,7 @@
                 DISPLAY_BOUNDS.right - 100, DISPLAY_BOUNDS.bottom - 100,
                 DISPLAY_BOUNDS.right, DISPLAY_BOUNDS.bottom);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
             arg0.set(DISPLAY_BOUNDS);
@@ -269,6 +277,7 @@
         final Rect expected = new Rect(
                 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         when(mMockPipBoundsState.isStashed()).thenReturn(true);
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
@@ -289,6 +298,7 @@
         final Rect expected = new Rect(
                 0, DISPLAY_BOUNDS.bottom - 100, 100, DISPLAY_BOUNDS.bottom);
         when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(new Rect(0, 0, 0, 0));
         when(mMockPipBoundsState.isStashed()).thenReturn(true);
         doAnswer(invocation -> {
             Rect arg0 = invocation.getArgument(0);
@@ -301,4 +311,40 @@
 
         assertEquals(expected, outBounds);
     }
+
+    @Test
+    public void adjust_restoreBoundsPresent_appliesRestoreBounds() {
+        final Rect pipBounds = new Rect(0, 0, 100, 100);
+        final Rect restoreBounds = new Rect(50, 50, 150, 150);
+        when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(restoreBounds);
+        when(mMockPipBoundsState.hasUserMovedPip()).thenReturn(true);
+        doAnswer(invocation -> {
+            Rect arg0 = invocation.getArgument(0);
+            arg0.set(DISPLAY_BOUNDS);
+            return null;
+        }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+        final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+                mMockPipBoundsState, mMockPipBoundsAlgorithm);
+        assertEquals(restoreBounds, outBounds);
+    }
+
+    @Test
+    public void adjust_restoreBoundsCleared_boundsUnchanged() {
+        final Rect pipBounds = new Rect(0, 0, 100, 100);
+        final Rect restoreBounds = new Rect(0, 0, 0, 0);
+        when(mMockPipBoundsState.getBounds()).thenReturn(pipBounds);
+        when(mMockPipBoundsState.getRestoreBounds()).thenReturn(restoreBounds);
+        when(mMockPipBoundsState.hasUserMovedPip()).thenReturn(true);
+        doAnswer(invocation -> {
+            Rect arg0 = invocation.getArgument(0);
+            arg0.set(DISPLAY_BOUNDS);
+            return null;
+        }).when(mMockPipBoundsAlgorithm).getInsetBounds(any(Rect.class));
+
+        final Rect outBounds = mPipKeepClearAlgorithm.adjust(
+                mMockPipBoundsState, mMockPipBoundsAlgorithm);
+        assertEquals(pipBounds, outBounds);
+    }
 }
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 2c805e8..a17d08d 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
@@ -98,6 +98,7 @@
 import com.android.wm.shell.transition.Transitions
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier
 import java.util.Optional
 import java.util.function.Consumer
 import java.util.function.Supplier
@@ -181,6 +182,7 @@
     @Mock private lateinit var mockTaskPositionerFactory:
             DesktopModeWindowDecorViewModel.TaskPositionerFactory
     @Mock private lateinit var mockTaskPositioner: TaskPositioner
+    @Mock private lateinit var mockWindowDecorViewHostSupplier: WindowDecorViewHostSupplier<*>
     private lateinit var spyContext: TestableContext
 
     private val transactionFactory = Supplier<SurfaceControl.Transaction> {
@@ -230,6 +232,7 @@
                 mockGenericLinksParser,
                 mockAssistContentRequester,
                 mockMultiInstanceHelper,
+                mockWindowDecorViewHostSupplier,
                 mockDesktopModeWindowDecorFactory,
                 mockInputMonitorFactory,
                 transactionFactory,
@@ -1197,7 +1200,7 @@
         whenever(
             mockDesktopModeWindowDecorFactory.create(
                 any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(),
-                any(), any(), any(), any())
+                any(), any(), any(), any(), any())
         ).thenReturn(decoration)
         decoration.mTaskInfo = task
         whenever(decoration.isFocused).thenReturn(task.isFocused)
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 b9e542a0..7b68ddf 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
@@ -97,6 +97,8 @@
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 import kotlin.Unit;
 import kotlin.jvm.functions.Function0;
@@ -162,6 +164,10 @@
     @Mock
     private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
     @Mock
+    private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier;
+    @Mock
+    private WindowDecorViewHost mMockWindowDecorViewHost;
+    @Mock
     private TypedArray mMockRoundedCornersRadiusArray;
     @Mock
     private TestTouchEventListener mMockTouchEventListener;
@@ -233,6 +239,9 @@
                 any(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()))
                 .thenReturn(mMockHandleMenu);
         when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false);
+        when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay)))
+                .thenReturn(mMockWindowDecorViewHost);
+        when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
     }
 
     @After
@@ -504,6 +513,42 @@
     }
 
     @Test
+    public void updateRelayoutParams_handle_requestsAsyncViewHostRendering() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        // Make the task fullscreen so that its decoration is an App Handle.
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        // App Handles don't need to be rendered in sync with the task animation, per UX.
+        assertThat(relayoutParams.mAsyncViewHost).isTrue();
+    }
+
+    @Test
+    public void updateRelayoutParams_header_requestsSyncViewHostRendering() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        // Make the task freeform so that its decoration is an App Header.
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        // App Headers must be rendered in sync with the task animation, so it cannot be delayed.
+        assertThat(relayoutParams.mAsyncViewHost).isFalse();
+    }
+
+    @Test
     public void relayout_fullscreenTask_appliesTransactionImmediately() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
         final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
@@ -526,74 +571,7 @@
         spyWindowDecor.relayout(taskInfo);
 
         verify(mMockTransaction, never()).apply();
-        verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockTransaction);
-    }
-
-    @Test
-    public void relayout_fullscreenTask_doesNotCreateViewHostImmediately() {
-        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
-        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
-        spyWindowDecor.relayout(taskInfo);
-
-        verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
-    }
-
-    @Test
-    public void relayout_fullscreenTask_postsViewHostCreation() {
-        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
-        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-
-        ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-        spyWindowDecor.relayout(taskInfo);
-
-        verify(mMockHandler).post(runnableArgument.capture());
-        runnableArgument.getValue().run();
-        verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
-    }
-
-    @Test
-    public void relayout_freeformTask_createsViewHostImmediately() {
-        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
-        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        // Make non-resizable to avoid dealing with input-permissions (MONITOR_INPUT)
-        taskInfo.isResizeable = false;
-
-        spyWindowDecor.relayout(taskInfo);
-
-        verify(mMockSurfaceControlViewHostFactory).create(any(), any(), any());
-        verify(mMockHandler, never()).post(any());
-    }
-
-    @Test
-    public void relayout_removesExistingHandlerCallback() {
-        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
-        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-        spyWindowDecor.relayout(taskInfo);
-        verify(mMockHandler).post(runnableArgument.capture());
-
-        spyWindowDecor.relayout(taskInfo);
-
-        verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
-    }
-
-    @Test
-    public void close_removesExistingHandlerCallback() {
-        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
-        final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
-        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-        spyWindowDecor.relayout(taskInfo);
-        verify(mMockHandler).post(runnableArgument.capture());
-
-        spyWindowDecor.close();
-
-        verify(mMockHandler).removeCallbacks(runnableArgument.getValue());
+        verify(mMockWindowDecorViewHost).updateView(any(), any(), any(), eq(mMockTransaction));
     }
 
     @Test
@@ -924,7 +902,8 @@
                 mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new,
                 mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
                 new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory,
-                maximizeMenuFactory, mMockHandleMenuFactory, mMockMultiInstanceHelper);
+                mMockWindowDecorViewHostSupplier, maximizeMenuFactory, mMockHandleMenuFactory,
+                mMockMultiInstanceHelper);
         windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener,
                 mMockTouchEventListener, mMockTouchEventListener);
         windowDecor.setExclusionRegionListener(mMockExclusionRegionListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 6154391c..7252b32 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -85,6 +85,8 @@
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.tests.R;
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -128,6 +130,10 @@
     @Mock
     private SurfaceControlViewHost mMockSurfaceControlViewHost;
     @Mock
+    private WindowDecorViewHostSupplier mMockWindowDecorViewHostSupplier;
+    @Mock
+    private WindowDecorViewHost mMockWindowDecorViewHost;
+    @Mock
     private AttachedSurfaceControl mMockRootSurfaceControl;
     @Mock
     private TestView mMockView;
@@ -167,6 +173,9 @@
         when(mMockSurfaceControlViewHost.getRootSurfaceControl())
                 .thenReturn(mMockRootSurfaceControl);
         when(mMockView.findViewById(anyInt())).thenReturn(mMockView);
+        when(mMockWindowDecorViewHostSupplier.acquire(any(), any()))
+                .thenReturn(mMockWindowDecorViewHost);
+        when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
 
         // Add status bar inset so that WindowDecoration does not think task is in immersive mode
         mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, statusBars()).setVisible(true);
@@ -230,10 +239,6 @@
         final SurfaceControl.Builder decorContainerSurfaceBuilder =
                 createMockSurfaceControlBuilder(decorContainerSurface);
         mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
-        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
-        final SurfaceControl.Builder captionContainerSurfaceBuilder =
-                createMockSurfaceControlBuilder(captionContainerSurface);
-        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
                 .setDisplayId(Display.DEFAULT_DISPLAY)
@@ -254,18 +259,18 @@
         verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true);
         verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 300, 100);
 
-        verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
-        verify(captionContainerSurfaceBuilder).setContainerLayer();
+        final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl();
+        verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface);
         verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
         verify(mMockSurfaceControlStartT).show(captionContainerSurface);
 
-        verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
-
-        verify(mMockSurfaceControlViewHost)
-                .setView(same(mMockView),
-                        argThat(lp -> lp.height == 64
-                                && lp.width == 300
-                                && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0));
+        verify(mMockWindowDecorViewHost).updateView(
+                same(mMockView),
+                argThat(lp -> lp.height == 64
+                        && lp.width == 300
+                        && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0),
+                eq(taskInfo.configuration),
+                eq(null) /* onDrawTransaction */);
         verify(mMockView).setTaskFocusState(true);
         verify(mMockWindowContainerTransaction).addInsetsSource(
                 eq(taskInfo.token),
@@ -296,10 +301,6 @@
         final SurfaceControl.Builder decorContainerSurfaceBuilder =
                 createMockSurfaceControlBuilder(decorContainerSurface);
         mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
-        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
-        final SurfaceControl.Builder captionContainerSurfaceBuilder =
-                createMockSurfaceControlBuilder(captionContainerSurface);
-        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
         mMockSurfaceControlTransactions.add(t);
@@ -322,7 +323,7 @@
 
         windowDecor.relayout(taskInfo);
 
-        verify(mMockSurfaceControlViewHost, never()).release();
+        verify(mMockWindowDecorViewHost, never()).release(any());
         verify(t, never()).apply();
         verify(mMockWindowContainerTransaction, never())
                 .removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
@@ -332,9 +333,8 @@
         taskInfo.isVisible = false;
         windowDecor.relayout(taskInfo);
 
-        final InOrder releaseOrder = inOrder(t2, mMockSurfaceControlViewHost);
-        releaseOrder.verify(mMockSurfaceControlViewHost).release();
-        releaseOrder.verify(t2).remove(captionContainerSurface);
+        final InOrder releaseOrder = inOrder(t2, mMockWindowDecorViewHostSupplier);
+        releaseOrder.verify(mMockWindowDecorViewHostSupplier).release(mMockWindowDecorViewHost, t2);
         releaseOrder.verify(t2).remove(decorContainerSurface);
         releaseOrder.verify(t2).apply();
         // Expect to remove two insets sources, the caption insets and the mandatory gesture insets.
@@ -382,8 +382,8 @@
         verify(mMockDisplayController).removeDisplayWindowListener(same(listener));
 
         assertThat(mRelayoutResult.mRootView).isSameInstanceAs(mMockView);
-        verify(mMockSurfaceControlViewHostFactory).create(any(), eq(mockDisplay), any());
-        verify(mMockSurfaceControlViewHost).setView(same(mMockView), any());
+        verify(mMockWindowDecorViewHostSupplier).acquire(any(), eq(mockDisplay));
+        verify(mMockWindowDecorViewHost).updateView(same(mMockView), any(), any(), any());
     }
 
     @Test
@@ -396,10 +396,6 @@
         final SurfaceControl.Builder decorContainerSurfaceBuilder =
                 createMockSurfaceControlBuilder(decorContainerSurface);
         mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
-        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
-        final SurfaceControl.Builder captionContainerSurfaceBuilder =
-                createMockSurfaceControlBuilder(captionContainerSurface);
-        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
         mMockSurfaceControlTransactions.add(t);
@@ -436,8 +432,7 @@
                 windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId);
         verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
         verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
-        verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
-                .create(any(), eq(defaultDisplay), any());
+        verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
     }
 
     @Test
@@ -450,10 +445,6 @@
         final SurfaceControl.Builder decorContainerSurfaceBuilder =
                 createMockSurfaceControlBuilder(decorContainerSurface);
         mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
-        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
-        final SurfaceControl.Builder captionContainerSurfaceBuilder =
-                createMockSurfaceControlBuilder(captionContainerSurface);
-        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
         mMockSurfaceControlTransactions.add(t);
@@ -473,8 +464,8 @@
 
         windowDecor.relayout(taskInfo);
 
-        verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
-        verify(captionContainerSurfaceBuilder).setContainerLayer();
+        final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl();
+        verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface);
         // Width of the captionContainerSurface should match the width of TASK_BOUNDS
         verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
         verify(mMockSurfaceControlStartT).show(captionContainerSurface);
@@ -490,10 +481,6 @@
         final SurfaceControl.Builder decorContainerSurfaceBuilder =
                 createMockSurfaceControlBuilder(decorContainerSurface);
         mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
-        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
-        final SurfaceControl.Builder captionContainerSurfaceBuilder =
-                createMockSurfaceControlBuilder(captionContainerSurface);
-        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
         mMockSurfaceControlTransactions.add(t);
@@ -511,9 +498,11 @@
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
 
-        windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */);
+        mRelayoutParams.mApplyStartTransactionOnDraw = true;
+        windowDecor.relayout(taskInfo);
 
-        verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+        verify(mMockWindowDecorViewHost).updateView(any(), any(), any(),
+                eq(mMockSurfaceControlStartT));
     }
 
     @Test
@@ -867,42 +856,58 @@
     }
 
     @Test
-    public void updateViewHost_applyTransactionOnDrawIsTrue_surfaceControlIsUpdated() {
+    public void relayout_applyTransactionOnDrawIsTrue_updatesViewWithDrawTransaction() {
         final TestWindowDecoration windowDecor = createWindowDecoration(
-                new TestRunningTaskInfoBuilder().build());
+                new TestRunningTaskInfoBuilder()
+                        .setVisible(true)
+                        .setWindowingMode(WINDOWING_MODE_FREEFORM)
+                        .build());
         mRelayoutParams.mApplyStartTransactionOnDraw = true;
         mRelayoutResult.mRootView = mMockView;
 
-        windowDecor.updateViewHost(mRelayoutParams, mMockSurfaceControlStartT, mRelayoutResult);
+        windowDecor.relayout(windowDecor.mTaskInfo);
 
-        verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+        verify(mMockWindowDecorViewHost)
+                .updateView(eq(mRelayoutResult.mRootView), any(),
+                        eq(windowDecor.mTaskInfo.configuration), eq(mMockSurfaceControlStartT));
     }
 
     @Test
-    public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsTrue_throwsException() {
+    public void relayout_applyTransactionOnDrawIsTrue_asyncViewHostRendering_throwsException() {
         final TestWindowDecoration windowDecor = createWindowDecoration(
-                new TestRunningTaskInfoBuilder().build());
+                new TestRunningTaskInfoBuilder()
+                        .setVisible(true)
+                        .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                        .build());
         mRelayoutParams.mApplyStartTransactionOnDraw = true;
+        mRelayoutParams.mAsyncViewHost = true;
         mRelayoutResult.mRootView = mMockView;
 
         assertThrows(IllegalArgumentException.class,
-                () -> windowDecor.updateViewHost(
-                        mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult));
+                () -> windowDecor.relayout(windowDecor.mTaskInfo));
     }
 
     @Test
-    public void updateViewHost_nullDrawTransaction_applyTransactionOnDrawIsFalse_doesNotThrow() {
+    public void relayout_asyncViewHostRendering() {
         final TestWindowDecoration windowDecor = createWindowDecoration(
-                new TestRunningTaskInfoBuilder().build());
-        mRelayoutParams.mApplyStartTransactionOnDraw = false;
+                new TestRunningTaskInfoBuilder()
+                        .setVisible(true)
+                        .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                        .build());
+        mRelayoutParams.mAsyncViewHost = true;
         mRelayoutResult.mRootView = mMockView;
 
-        windowDecor.updateViewHost(mRelayoutParams, null /* onDrawTransaction */, mRelayoutResult);
+        windowDecor.relayout(windowDecor.mTaskInfo);
+
+        verify(mMockWindowDecorViewHost)
+                .updateViewAsync(eq(mRelayoutResult.mRootView), any(),
+                        eq(windowDecor.mTaskInfo.configuration));
     }
 
     @Test
-    public void onStatusBarVisibilityChange_shownToHidden_hidesCaption() {
+    public void onStatusBarVisibilityChange_fullscreen_shownToHidden_hidesCaption() {
         final ActivityManager.RunningTaskInfo task = createTaskInfo();
+        task.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         when(mMockDisplayController.getInsetsState(task.displayId))
                 .thenReturn(createInsetsState(statusBars(), true /* visible */));
         final TestWindowDecoration decor = createWindowDecoration(task);
@@ -915,8 +920,9 @@
     }
 
     @Test
-    public void onStatusBarVisibilityChange_hiddenToShown_showsCaption() {
+    public void onStatusBarVisibilityChange_fullscreen_hiddenToShown_showsCaption() {
         final ActivityManager.RunningTaskInfo task = createTaskInfo();
+        task.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         when(mMockDisplayController.getInsetsState(task.displayId))
                 .thenReturn(createInsetsState(statusBars(), false /* visible */));
         final TestWindowDecoration decor = createWindowDecoration(task);
@@ -929,6 +935,21 @@
     }
 
     @Test
+    public void onStatusBarVisibilityChange_freeform_shownToHidden_keepsCaption() {
+        final ActivityManager.RunningTaskInfo task = createTaskInfo();
+        task.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        when(mMockDisplayController.getInsetsState(task.displayId))
+                .thenReturn(createInsetsState(statusBars(), true /* visible */));
+        final TestWindowDecoration decor = createWindowDecoration(task);
+        decor.relayout(task);
+        assertTrue(decor.mIsCaptionVisible);
+
+        decor.onInsetsStateChanged(createInsetsState(statusBars(), false /* visible */));
+
+        assertTrue(decor.mIsCaptionVisible);
+    }
+
+    @Test
     public void onKeyguardStateChange_hiddenToShownAndOccluding_hidesCaption() {
         final ActivityManager.RunningTaskInfo task = createTaskInfo();
         when(mMockDisplayController.getInsetsState(task.displayId))
@@ -980,7 +1001,8 @@
                 new MockObjectSupplier<>(mMockSurfaceControlTransactions,
                         () -> mock(SurfaceControl.Transaction.class)),
                 () -> mMockWindowContainerTransaction, () -> mMockTaskSurface,
-                mMockSurfaceControlViewHostFactory);
+                mMockSurfaceControlViewHostFactory,
+                mMockWindowDecorViewHostSupplier);
     }
 
     private class MockObjectSupplier<T> implements Supplier<T> {
@@ -1020,16 +1042,20 @@
                 Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
                 Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
                 Supplier<SurfaceControl> surfaceControlSupplier,
-                SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
+                SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+                @NonNull WindowDecorViewHostSupplier windowDecorViewHostSupplier) {
             super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface,
                     surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
                     windowContainerTransactionSupplier, surfaceControlSupplier,
-                    surfaceControlViewHostFactory);
+                    surfaceControlViewHostFactory, windowDecorViewHostSupplier);
         }
 
         @Override
         void relayout(ActivityManager.RunningTaskInfo taskInfo) {
-            relayout(taskInfo, false /* applyStartTransactionOnDraw */);
+            mRelayoutParams.mRunningTaskInfo = taskInfo;
+            mRelayoutParams.mLayoutResId = R.layout.caption_layout;
+            relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
+                    mMockWindowContainerTransaction, mMockView, mRelayoutResult);
         }
 
         @Override
@@ -1050,15 +1076,6 @@
             return super.inflateLayout(context, layoutResId);
         }
 
-        void relayout(ActivityManager.RunningTaskInfo taskInfo,
-                boolean applyStartTransactionOnDraw) {
-            mRelayoutParams.mRunningTaskInfo = taskInfo;
-            mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
-            mRelayoutParams.mLayoutResId = R.layout.caption_layout;
-            relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
-                    mMockWindowContainerTransaction, mMockView, mRelayoutResult);
-        }
-
         private AdditionalViewContainer addTestViewContainer() {
             final Resources resources = mDecorWindowContext.getResources();
             final int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
new file mode 100644
index 0000000..1b2ce9e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.viewhost
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+
+/**
+ * Tests for [DefaultWindowDecorViewHost].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:DefaultWindowDecorViewHostTest
+ */
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DefaultWindowDecorViewHostTest : ShellTestCase() {
+
+    @Test
+    fun updateView_layoutInViewHost() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null
+        )
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+    }
+
+    @Test
+    fun updateView_alreadyLaidOut_relayouts() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null
+        )
+
+        val otherParams = WindowManager.LayoutParams(200, 200)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = otherParams,
+            configuration = context.resources.configuration,
+            onDrawTransaction = null
+        )
+
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
+        assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+            .isEqualTo(otherParams.width)
+    }
+
+    @Test
+    fun updateView_replacingView_throws() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null
+        )
+
+        val otherView = View(context)
+        assertThrows(Exception::class.java) {
+            windowDecorViewHost.updateView(
+                view = otherView,
+                attrs = WindowManager.LayoutParams(100, 100),
+                configuration = context.resources.configuration,
+                onDrawTransaction = null
+            )
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun updateView_clearsPendingAsyncJob() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val asyncView = View(context)
+        val syncView = View(context)
+        val asyncAttrs = WindowManager.LayoutParams(100, 100)
+        val syncAttrs = WindowManager.LayoutParams(200, 200)
+
+        windowDecorViewHost.updateViewAsync(
+            view = asyncView,
+            attrs = asyncAttrs,
+            configuration = context.resources.configuration,
+        )
+
+        // No view host yet, since the coroutine hasn't run.
+        assertThat(windowDecorViewHost.viewHost).isNull()
+
+        windowDecorViewHost.updateView(
+            view = syncView,
+            attrs = syncAttrs,
+            configuration = context.resources.configuration,
+            onDrawTransaction = null
+        )
+
+        // Would run coroutine if it hadn't been cancelled.
+        advanceUntilIdle()
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+        // View host view/attrs should match the ones from the sync call, plus, since the
+        // sync/async were made with different views, if the job hadn't been cancelled there
+        // would've been an exception thrown as replacing views isn't allowed.
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(syncView)
+        assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
+            .isEqualTo(syncAttrs.width)
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun updateViewAsync() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+        val view = View(context)
+        val attrs = WindowManager.LayoutParams(100, 100)
+
+        windowDecorViewHost.updateViewAsync(
+            view = view,
+            attrs = attrs,
+            configuration = context.resources.configuration,
+        )
+
+        assertThat(windowDecorViewHost.viewHost).isNull()
+
+        advanceUntilIdle()
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    fun updateViewAsync_clearsPendingAsyncJob() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+
+        val view = View(context)
+        windowDecorViewHost.updateViewAsync(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+        )
+        val otherView = View(context)
+        windowDecorViewHost.updateViewAsync(
+            view = otherView,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+        )
+
+        advanceUntilIdle()
+
+        assertThat(windowDecorViewHost.viewHost).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+        assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(otherView)
+    }
+
+    @Test
+    fun release() = runTest {
+        val windowDecorViewHost = createDefaultViewHost()
+
+        val view = View(context)
+        windowDecorViewHost.updateView(
+            view = view,
+            attrs = WindowManager.LayoutParams(100, 100),
+            configuration = context.resources.configuration,
+            onDrawTransaction = null
+        )
+
+        val t = mock(SurfaceControl.Transaction::class.java)
+        windowDecorViewHost.release(t)
+
+        verify(windowDecorViewHost.viewHost!!).release()
+        verify(t).remove(windowDecorViewHost.surfaceControl)
+    }
+
+    private fun CoroutineScope.createDefaultViewHost() = DefaultWindowDecorViewHost(
+        context = context,
+        mainScope = this,
+        display = context.display,
+        surfaceControlViewHostFactory = { c, d, wwm, s ->
+            spy(SurfaceControlViewHost(c, d, wwm, s))
+        }
+    )
+}
\ No newline at end of file
diff --git a/libs/appfunctions/OWNERS b/libs/appfunctions/OWNERS
new file mode 100644
index 0000000..c093675
--- /dev/null
+++ b/libs/appfunctions/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include /core/java/android/app/appfunctions/OWNERS
diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp
index 5a45ad9..8deac61 100644
--- a/libs/hwui/SkiaInterpolator.cpp
+++ b/libs/hwui/SkiaInterpolator.cpp
@@ -47,6 +47,8 @@
     return static_cast<Dot14>(x * Dot14_ONE);
 }
 
+using MSec = uint32_t;  // millisecond duration
+
 static float SkUnitCubicInterp(float value, float bx, float by, float cx, float cy) {
     // pin to the unit-square, and convert to 2.14
     Dot14 x = pin_and_convert(value);
@@ -120,7 +122,7 @@
     Totaling fElemCount+2 entries per keyframe
 */
 
-bool SkiaInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const {
+bool SkiaInterpolatorBase::getDuration(MSec* startTime, MSec* endTime) const {
     if (fFrameCount == 0) {
         return false;
     }
@@ -134,7 +136,7 @@
     return true;
 }
 
-float SkiaInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime,
+float SkiaInterpolatorBase::ComputeRelativeT(MSec time, MSec prevTime, MSec nextTime,
                                              const float blend[4]) {
     LOG_FATAL_IF(time < prevTime || time > nextTime);
 
@@ -144,7 +146,7 @@
 
 // Returns the index of where the item is or the bit not of the index
 // where the item should go in order to keep arr sorted in ascending order.
-int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, SkMSec target) {
+int SkiaInterpolatorBase::binarySearch(const SkTimeCode* arr, int count, MSec target) {
     if (count <= 0) {
         return ~0;
     }
@@ -154,7 +156,7 @@
 
     while (lo < hi) {
         int mid = (hi + lo) / 2;
-        SkMSec elem = arr[mid].fTime;
+        MSec elem = arr[mid].fTime;
         if (elem == target) {
             return mid;
         } else if (elem < target) {
@@ -171,21 +173,21 @@
     return ~(lo + 1);
 }
 
-SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(SkMSec time, float* T, int* indexPtr,
+SkiaInterpolatorBase::Result SkiaInterpolatorBase::timeToT(MSec time, float* T, int* indexPtr,
                                                            bool* exactPtr) const {
     LOG_FATAL_IF(fFrameCount <= 0);
     Result result = kNormal_Result;
     if (fRepeat != 1.0f) {
-        SkMSec startTime = 0, endTime = 0;  // initialize to avoid warning
+        MSec startTime = 0, endTime = 0;  // initialize to avoid warning
         this->getDuration(&startTime, &endTime);
-        SkMSec totalTime = endTime - startTime;
-        SkMSec offsetTime = time - startTime;
+        MSec totalTime = endTime - startTime;
+        MSec offsetTime = time - startTime;
         endTime = SkScalarFloorToInt(fRepeat * totalTime);
         if (offsetTime >= endTime) {
             float fraction = SkScalarFraction(fRepeat);
             offsetTime = fraction == 0 && fRepeat > 0
                                  ? totalTime
-                                 : (SkMSec)SkScalarFloorToInt(fraction * totalTime);
+                                 : (MSec)SkScalarFloorToInt(fraction * totalTime);
             result = kFreezeEnd_Result;
         } else {
             int mirror = fFlags & kMirror;
@@ -217,11 +219,11 @@
     }
     LOG_FATAL_IF(index >= fFrameCount);
     const SkTimeCode* nextTime = &fTimes[index];
-    SkMSec nextT = nextTime[0].fTime;
+    MSec nextT = nextTime[0].fTime;
     if (exact) {
         *T = 0;
     } else {
-        SkMSec prevT = nextTime[-1].fTime;
+        MSec prevT = nextTime[-1].fTime;
         *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
     }
     *indexPtr = index;
@@ -251,7 +253,7 @@
 
 static const float gIdentityBlend[4] = {0.33333333f, 0.33333333f, 0.66666667f, 0.66666667f};
 
-bool SkiaInterpolator::setKeyFrame(int index, SkMSec time, const float values[],
+bool SkiaInterpolator::setKeyFrame(int index, MSec time, const float values[],
                                    const float blend[4]) {
     LOG_FATAL_IF(values == nullptr);
 
@@ -272,7 +274,7 @@
     return success;
 }
 
-SkiaInterpolator::Result SkiaInterpolator::timeToValues(SkMSec time, float values[]) const {
+SkiaInterpolator::Result SkiaInterpolator::timeToValues(MSec time, float values[]) const {
     float T;
     int index;
     bool exact;
diff --git a/libs/hwui/jni/GIFMovie.cpp b/libs/hwui/jni/GIFMovie.cpp
index ae6ac4c..6c82aa1 100644
--- a/libs/hwui/jni/GIFMovie.cpp
+++ b/libs/hwui/jni/GIFMovie.cpp
@@ -30,7 +30,7 @@
 
 protected:
     virtual bool onGetInfo(Info*);
-    virtual bool onSetTime(SkMSec);
+    virtual bool onSetTime(Movie::MSec);
     virtual bool onGetBitmap(SkBitmap*);
 
 private:
@@ -72,7 +72,7 @@
         DGifCloseFile(fGIF, nullptr);
 }
 
-static SkMSec savedimage_duration(const SavedImage* image)
+static Movie::MSec savedimage_duration(const SavedImage* image)
 {
     for (int j = 0; j < image->ExtensionBlockCount; j++)
     {
@@ -91,7 +91,7 @@
     if (nullptr == fGIF)
         return false;
 
-    SkMSec dur = 0;
+    Movie::MSec dur = 0;
     for (int i = 0; i < fGIF->ImageCount; i++)
         dur += savedimage_duration(&fGIF->SavedImages[i]);
 
@@ -102,12 +102,12 @@
     return true;
 }
 
-bool GIFMovie::onSetTime(SkMSec time)
+bool GIFMovie::onSetTime(Movie::MSec time)
 {
     if (nullptr == fGIF)
         return false;
 
-    SkMSec dur = 0;
+    Movie::MSec dur = 0;
     for (int i = 0; i < fGIF->ImageCount; i++)
     {
         dur += savedimage_duration(&fGIF->SavedImages[i]);
diff --git a/libs/hwui/jni/Movie.h b/libs/hwui/jni/Movie.h
index 02113dd..d633d93 100644
--- a/libs/hwui/jni/Movie.h
+++ b/libs/hwui/jni/Movie.h
@@ -19,6 +19,8 @@
 
 class Movie : public SkRefCnt {
 public:
+    using MSec = uint32_t; // millisecond duration
+
     /** Try to create a movie from the stream. If the stream format is not
         supported, return NULL.
     */
@@ -36,7 +38,7 @@
     */
     static Movie* DecodeMemory(const void* data, size_t length);
 
-    SkMSec  duration();
+    MSec    duration();
     int     width();
     int     height();
     int     isOpaque();
@@ -46,21 +48,21 @@
         bitmap/frame from the previous state (i.e. true means you need to
         redraw).
     */
-    bool setTime(SkMSec);
+    bool setTime(MSec);
 
     // return the right bitmap for the current time code
     const SkBitmap& bitmap();
 
 protected:
     struct Info {
-        SkMSec  fDuration;
+        MSec    fDuration;
         int     fWidth;
         int     fHeight;
         bool    fIsOpaque;
     };
 
     virtual bool onGetInfo(Info*) = 0;
-    virtual bool onSetTime(SkMSec) = 0;
+    virtual bool onSetTime(MSec) = 0;
     virtual bool onGetBitmap(SkBitmap*) = 0;
 
     // visible for subclasses
@@ -68,7 +70,7 @@
 
 private:
     Info        fInfo;
-    SkMSec      fCurrTime;
+    MSec        fCurrTime;
     SkBitmap    fBitmap;
     bool        fNeedBitmap;
 
diff --git a/libs/hwui/jni/MovieImpl.cpp b/libs/hwui/jni/MovieImpl.cpp
index abb75fa..a31a15f 100644
--- a/libs/hwui/jni/MovieImpl.cpp
+++ b/libs/hwui/jni/MovieImpl.cpp
@@ -11,7 +11,7 @@
 
 // We should never see this in normal operation since our time values are
 // 0-based. So we use it as a sentinel.
-#define UNINITIALIZED_MSEC ((SkMSec)-1)
+#define UNINITIALIZED_MSEC ((Movie::MSec)-1)
 
 Movie::Movie()
 {
@@ -26,7 +26,7 @@
         memset(&fInfo, 0, sizeof(fInfo));   // failure
 }
 
-SkMSec Movie::duration()
+Movie::MSec Movie::duration()
 {
     this->ensureInfo();
     return fInfo.fDuration;
@@ -50,9 +50,9 @@
     return fInfo.fIsOpaque;
 }
 
-bool Movie::setTime(SkMSec time)
+bool Movie::setTime(Movie::MSec time)
 {
-    SkMSec dur = this->duration();
+    Movie::MSec dur = this->duration();
     if (time > dur)
         time = dur;
 
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index bbd91fc..dcf5c5b 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -116,4 +116,7 @@
     description: "Flag for enabling NI SUPL message injection by carrier config"
     bug: "242105192"
     is_fixed_read_only: true
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS
index 880ec8f..2b72744 100644
--- a/media/java/android/media/projection/OWNERS
+++ b/media/java/android/media/projection/OWNERS
@@ -1,7 +1,7 @@
 # Bug component: 1345447
 
-michaelwr@google.com
-santoscordon@google.com
-chaviw@google.com
-nmusgrave@google.com
+marvinramin@google.com
 dakinola@google.com
+vaniadesmonda@google.com
+caen@google.com
+santoscordon@google.com
\ No newline at end of file
diff --git a/media/tests/LoudnessCodecApiTest/Android.bp b/media/tests/LoudnessCodecApiTest/Android.bp
index 5ca0fc9..5d1153d 100644
--- a/media/tests/LoudnessCodecApiTest/Android.bp
+++ b/media/tests/LoudnessCodecApiTest/Android.bp
@@ -25,3 +25,10 @@
     resource_dirs: ["res"],
     test_suites: ["device-tests"],
 }
+
+test_module_config {
+    name: "LoudnessCodecApiTest_Presubmit",
+    base: "LoudnessCodecApiTest",
+    test_suites: ["device-tests"],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 346c87d..25c063d6 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -367,6 +367,7 @@
     APerformanceHint_sendHint;
     APerformanceHint_getThreadIds;
     APerformanceHint_createSessionInternal;
+    APerformanceHint_setUseFMQForTesting;
     extern "C++" {
         ASurfaceControl_registerSurfaceStatsListener*;
         ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index e91c7a9..095d7d1 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -16,10 +16,14 @@
 
 #define LOG_TAG "perf_hint"
 
+#include <aidl/android/hardware/power/ChannelConfig.h>
+#include <aidl/android/hardware/power/ChannelMessage.h>
+#include <aidl/android/hardware/power/SessionConfig.h>
 #include <aidl/android/hardware/power/SessionHint.h>
 #include <aidl/android/hardware/power/SessionMode.h>
 #include <aidl/android/hardware/power/SessionTag.h>
 #include <aidl/android/hardware/power/WorkDuration.h>
+#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
 #include <aidl/android/os/IHintManager.h>
 #include <aidl/android/os/IHintSession.h>
 #include <android-base/stringprintf.h>
@@ -28,6 +32,8 @@
 #include <android/binder_status.h>
 #include <android/performance_hint.h>
 #include <android/trace.h>
+#include <android_os.h>
+#include <fmq/AidlMessageQueue.h>
 #include <inttypes.h>
 #include <performance_hint_private.h>
 #include <utils/SystemClock.h>
@@ -45,6 +51,10 @@
 // Namespace for AIDL types coming from the PowerHAL
 namespace hal = aidl::android::hardware::power;
 
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
+using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
+using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 using android::base::StringPrintf;
 
 struct APerformanceHintSession;
@@ -54,18 +64,60 @@
 
 // Shared lock for the whole PerformanceHintManager and sessions
 static std::mutex sHintMutex = std::mutex{};
+class FMQWrapper {
+public:
+    bool isActive();
+    bool isSupported();
+    bool startChannel(IHintManager* manager);
+    void stopChannel(IHintManager* manager);
+    // Number of elements the FMQ can hold
+    bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
+                                   hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
+    bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
+                                  int64_t targetDurationNanos) REQUIRES(sHintMutex);
+    bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex);
+    bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
+            REQUIRES(sHintMutex);
+    void setToken(ndk::SpAIBinder& token);
+    void attemptWake();
+    void setUnsupported();
+
+private:
+    template <HalChannelMessageContents::Tag T, bool urgent = false,
+              class C = HalChannelMessageContents::_at<T>>
+    bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1)
+            REQUIRES(sHintMutex);
+    template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
+    void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex);
+
+    bool isActiveLocked() REQUIRES(sHintMutex);
+    bool updatePersistentTransaction() REQUIRES(sHintMutex);
+    std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
+    std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
+    // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
+    android::hardware::EventFlag* mEventFlag = nullptr;
+    int32_t mWriteMask;
+    ndk::SpAIBinder mToken = nullptr;
+    // Used to track if operating on the fmq consistently fails
+    bool mCorrupted = false;
+    // Used to keep a persistent transaction open with FMQ to reduce latency a bit
+    size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
+    bool mHalSupported = true;
+    HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
+};
 
 struct APerformanceHintManager {
 public:
     static APerformanceHintManager* getInstance();
-    APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
+    APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
     APerformanceHintManager() = delete;
-    ~APerformanceHintManager() = default;
+    ~APerformanceHintManager();
 
     APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
                                            int64_t initialTargetWorkDurationNanos,
                                            hal::SessionTag tag = hal::SessionTag::APP);
     int64_t getPreferredRateNanos() const;
+    FMQWrapper& getFMQWrapper();
 
 private:
     // Necessary to create an empty binder object
@@ -83,6 +135,7 @@
     std::shared_ptr<IHintManager> mHintManager;
     ndk::SpAIBinder mToken;
     const int64_t mPreferredRateNanos;
+    FMQWrapper mFMQWrapper;
 };
 
 struct APerformanceHintSession {
@@ -121,40 +174,57 @@
     std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
     // Cached samples
     std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
-    std::string mSessionName GUARDED_BY(sHintMutex);
+    std::string mSessionName;
     static int64_t sIDCounter GUARDED_BY(sHintMutex);
     // The most recent set of thread IDs
     std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
     std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
     // Tracing helpers
     void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
-    void tracePowerEfficient(bool powerEfficient) REQUIRES(sHintMutex);
-    void traceActualDuration(int64_t actualDuration) REQUIRES(sHintMutex);
-    void traceBatchSize(size_t batchSize) REQUIRES(sHintMutex);
-    void traceTargetDuration(int64_t targetDuration) REQUIRES(sHintMutex);
+    void tracePowerEfficient(bool powerEfficient);
+    void traceActualDuration(int64_t actualDuration);
+    void traceBatchSize(size_t batchSize);
+    void traceTargetDuration(int64_t targetDuration);
 };
 
 static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
-static APerformanceHintManager* gHintManagerForTesting = nullptr;
+static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
+
+static std::optional<bool> gForceFMQEnabled = std::nullopt;
+
 // Start above the int32 range so we don't collide with config sessions
 int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
 
+static FMQWrapper& getFMQ() {
+    return APerformanceHintManager::getInstance()->getFMQWrapper();
+}
+
 // ===================================== APerformanceHintManager implementation
-APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
+APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
                                                  int64_t preferredRateNanos)
       : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
     static AIBinder_Class* tokenBinderClass =
             AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
                                   tokenStubOnTransact);
     mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
+    if (mFMQWrapper.isSupported()) {
+        mFMQWrapper.setToken(mToken);
+        mFMQWrapper.startChannel(mHintManager.get());
+    }
+}
+
+APerformanceHintManager::~APerformanceHintManager() {
+    mFMQWrapper.stopChannel(mHintManager.get());
 }
 
 APerformanceHintManager* APerformanceHintManager::getInstance() {
-    if (gHintManagerForTesting) return gHintManagerForTesting;
+    if (gHintManagerForTesting) {
+        return gHintManagerForTesting.get();
+    }
     if (gIHintManagerForTesting) {
-        APerformanceHintManager* manager = create(*gIHintManagerForTesting);
-        gIHintManagerForTesting = nullptr;
-        return manager;
+        gHintManagerForTesting =
+                std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
+        return gHintManagerForTesting.get();
     }
     static APerformanceHintManager* instance = create(nullptr);
     return instance;
@@ -178,7 +248,7 @@
     if (preferredRateNanos <= 0) {
         preferredRateNanos = -1L;
     }
-    return new APerformanceHintManager(std::move(manager), preferredRateNanos);
+    return new APerformanceHintManager(manager, preferredRateNanos);
 }
 
 APerformanceHintSession* APerformanceHintManager::createSession(
@@ -187,15 +257,20 @@
     std::vector<int32_t> tids(threadIds, threadIds + size);
     std::shared_ptr<IHintSession> session;
     ndk::ScopedAStatus ret;
-    std::optional<hal::SessionConfig> sessionConfig;
+    hal::SessionConfig sessionConfig{.id = -1};
     ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
                                                     tag, &sessionConfig, &session);
 
     if (!ret.isOk() || !session) {
+        ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
         return nullptr;
     }
     auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
-                                           initialTargetWorkDurationNanos, sessionConfig);
+                                           initialTargetWorkDurationNanos,
+                                           sessionConfig.id == -1
+                                                   ? std::nullopt
+                                                   : std::make_optional<hal::SessionConfig>(
+                                                             std::move(sessionConfig)));
     std::scoped_lock lock(sHintMutex);
     out->traceThreads(tids);
     out->traceTargetDuration(initialTargetWorkDurationNanos);
@@ -207,8 +282,15 @@
     return mPreferredRateNanos;
 }
 
+FMQWrapper& APerformanceHintManager::getFMQWrapper() {
+    return mFMQWrapper;
+}
+
 // ===================================== APerformanceHintSession implementation
 
+constexpr int kNumEnums =
+        ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
+
 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
                                                  std::shared_ptr<IHintSession> session,
                                                  int64_t preferredRateNanos,
@@ -220,14 +302,11 @@
         mTargetDurationNanos(targetDurationNanos),
         mFirstTargetMetTimestamp(0),
         mLastTargetMetTimestamp(0),
+        mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
         mSessionConfig(sessionConfig) {
     if (sessionConfig->id > INT32_MAX) {
         ALOGE("Session ID too large, must fit 32-bit integer");
     }
-    std::scoped_lock lock(sHintMutex);
-    constexpr int numEnums =
-            ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
-    mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
     int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
     mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
 }
@@ -244,19 +323,18 @@
         ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
         return EINVAL;
     }
-    {
-        std::scoped_lock lock(sHintMutex);
-        if (mTargetDurationNanos == targetDurationNanos) {
-            return 0;
+    std::scoped_lock lock(sHintMutex);
+    if (mTargetDurationNanos == targetDurationNanos) {
+        return 0;
+    }
+    if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
+        ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
+        if (!ret.isOk()) {
+            ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
+                  ret.getMessage());
+            return EPIPE;
         }
     }
-    ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
-    if (!ret.isOk()) {
-        ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
-              ret.getMessage());
-        return EPIPE;
-    }
-    std::scoped_lock lock(sHintMutex);
     mTargetDurationNanos = targetDurationNanos;
     /**
      * Most of the workload is target_duration dependent, so now clear the cached samples
@@ -292,11 +370,13 @@
         return 0;
     }
 
-    ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
+    if (!getFMQ().sendHint(mSessionConfig, hint)) {
+        ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
 
-    if (!ret.isOk()) {
-        ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
-        return EPIPE;
+        if (!ret.isOk()) {
+            ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
+            return EPIPE;
+        }
     }
     mLastHintSentTimestamp[hint] = now;
     return 0;
@@ -369,10 +449,10 @@
 
 int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
     int64_t actualTotalDurationNanos = workDuration->durationNanos;
+    traceActualDuration(workDuration->durationNanos);
     int64_t now = uptimeNanos();
     workDuration->timeStampNanos = now;
     std::scoped_lock lock(sHintMutex);
-    traceActualDuration(workDuration->durationNanos);
     mActualWorkDurations.push_back(std::move(*workDuration));
 
     if (actualTotalDurationNanos >= mTargetDurationNanos) {
@@ -396,20 +476,177 @@
         mLastTargetMetTimestamp = now;
     }
 
-    ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
-    if (!ret.isOk()) {
-        ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
-              ret.getMessage());
-        mFirstTargetMetTimestamp = 0;
-        mLastTargetMetTimestamp = 0;
-        traceBatchSize(mActualWorkDurations.size());
-        return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
+    if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
+                                            mActualWorkDurations.size())) {
+        ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
+        if (!ret.isOk()) {
+            ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
+                  ret.getMessage());
+            mFirstTargetMetTimestamp = 0;
+            mLastTargetMetTimestamp = 0;
+            traceBatchSize(mActualWorkDurations.size());
+            return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
+        }
     }
+
     mActualWorkDurations.clear();
     traceBatchSize(0);
 
     return 0;
 }
+
+// ===================================== FMQ wrapper implementation
+
+bool FMQWrapper::isActive() {
+    std::scoped_lock lock{sHintMutex};
+    return isActiveLocked();
+}
+
+bool FMQWrapper::isActiveLocked() {
+    return mQueue != nullptr;
+}
+
+void FMQWrapper::setUnsupported() {
+    mHalSupported = false;
+}
+
+bool FMQWrapper::isSupported() {
+    if (!mHalSupported) {
+        return false;
+    }
+    // Used for testing
+    if (gForceFMQEnabled.has_value()) {
+        return *gForceFMQEnabled;
+    }
+    return android::os::adpf_use_fmq_channel_fixed();
+}
+
+bool FMQWrapper::startChannel(IHintManager* manager) {
+    if (isSupported() && !isActive()) {
+        std::optional<hal::ChannelConfig> config;
+        auto ret = manager->getSessionChannel(mToken, &config);
+        if (ret.isOk() && config.has_value()) {
+            std::scoped_lock lock{sHintMutex};
+            mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
+            if (config->eventFlagDescriptor.has_value()) {
+                mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
+                android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
+                                                              &mEventFlag);
+                mWriteMask = config->writeFlagBitmask;
+            }
+            updatePersistentTransaction();
+        } else if (ret.isOk() && !config.has_value()) {
+            ALOGV("FMQ channel enabled but unsupported.");
+            setUnsupported();
+        } else {
+            ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
+        }
+    }
+    return isActive();
+}
+
+void FMQWrapper::stopChannel(IHintManager* manager) {
+    {
+        std::scoped_lock lock{sHintMutex};
+        if (!isActiveLocked()) {
+            return;
+        }
+        mFlagQueue = nullptr;
+        mQueue = nullptr;
+    }
+    manager->closeSessionChannel();
+}
+
+template <HalChannelMessageContents::Tag T, class C>
+void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) {
+    new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{
+            .sessionID = static_cast<int32_t>(config.id),
+            .timeStampNanos = ::android::uptimeNanos(),
+            .data = HalChannelMessageContents::make<T, C>(std::move(*message)),
+    };
+}
+
+template <>
+void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
+                                                                      hal::SessionConfig& config,
+                                                                      size_t count) {
+    for (size_t i = 0; i < count; ++i) {
+        hal::WorkDuration& message = messages[i];
+        new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
+                .sessionID = static_cast<int32_t>(config.id),
+                .timeStampNanos =
+                        (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos,
+                .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
+                                                        hal::WorkDurationFixedV1>({
+                        .durationNanos = message.cpuDurationNanos,
+                        .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
+                        .cpuDurationNanos = message.cpuDurationNanos,
+                        .gpuDurationNanos = message.gpuDurationNanos,
+                }),
+        };
+    }
+}
+
+template <HalChannelMessageContents::Tag T, bool urgent, class C>
+bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) {
+    if (!isActiveLocked() || !config.has_value() || mCorrupted) {
+        return false;
+    }
+    // If we didn't reserve enough space, try re-creating the transaction
+    if (count > mAvailableSlots) {
+        if (!updatePersistentTransaction()) {
+            return false;
+        }
+        // If we actually don't have enough space, give up
+        if (count > mAvailableSlots) {
+            return false;
+        }
+    }
+    writeBuffer<T, C>(message, *config, count);
+    mQueue->commitWrite(count);
+    mEventFlag->wake(mWriteMask);
+    // Re-create the persistent transaction after writing
+    updatePersistentTransaction();
+    return true;
+}
+
+void FMQWrapper::setToken(ndk::SpAIBinder& token) {
+    mToken = token;
+}
+
+bool FMQWrapper::updatePersistentTransaction() {
+    mAvailableSlots = mQueue->availableToWrite();
+    if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
+        ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
+        mCorrupted = true;
+        return false;
+    }
+    return true;
+}
+
+bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
+                                           hal::WorkDuration* durations, size_t count) {
+    return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
+}
+
+bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
+                                          int64_t targetDurationNanos) {
+    return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
+}
+
+bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) {
+    return sendMessages<HalChannelMessageContents::hint>(config,
+                                                         reinterpret_cast<hal::SessionHint*>(
+                                                                 &hint));
+}
+
+bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
+                         bool enabled) {
+    hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
+                                                                           .enabled = enabled};
+    return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
+}
+
 // ===================================== Tracing helpers
 
 void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
@@ -585,7 +822,12 @@
 }
 
 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
-    delete gHintManagerForTesting;
-    gHintManagerForTesting = nullptr;
+    if (iManager == nullptr) {
+        gHintManagerForTesting = nullptr;
+    }
     gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
 }
+
+void APerformanceHint_setUseFMQForTesting(bool enabled) {
+    gForceFMQEnabled = enabled;
+}
diff --git a/native/android/tests/performance_hint/Android.bp b/native/android/tests/performance_hint/Android.bp
index 608d5d8..f6f1da1 100644
--- a/native/android/tests/performance_hint/Android.bp
+++ b/native/android/tests/performance_hint/Android.bp
@@ -36,10 +36,13 @@
     srcs: ["PerformanceHintNativeTest.cpp"],
 
     shared_libs: [
+        "android.hardware.common.fmq-V1-ndk",
         "libandroid",
-        "liblog",
         "libbinder",
         "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
         "libpowermanager",
         "libutils",
     ],
@@ -56,8 +59,8 @@
     ],
 
     cflags: [
-        "-Werror",
         "-Wall",
+        "-Werror",
     ],
 
     header_libs: [
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index d19fa98..9de3a6f 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -24,6 +24,7 @@
 #include <android/binder_manager.h>
 #include <android/binder_status.h>
 #include <android/performance_hint.h>
+#include <fmq/AidlMessageQueue.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <performance_hint_private.h>
@@ -31,11 +32,16 @@
 #include <memory>
 #include <vector>
 
+using namespace std::chrono_literals;
 namespace hal = aidl::android::hardware::power;
 using aidl::android::os::IHintManager;
 using aidl::android::os::IHintSession;
 using ndk::ScopedAStatus;
 using ndk::SpAIBinder;
+using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
+
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
 
 using namespace android;
 using namespace testing;
@@ -44,7 +50,7 @@
 public:
     MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
                 (const SpAIBinder& token, const ::std::vector<int32_t>& tids, int64_t durationNanos,
-                 hal::SessionTag tag, std::optional<hal::SessionConfig>* config,
+                 hal::SessionTag tag, hal::SessionConfig* config,
                  std::shared_ptr<IHintSession>* _aidl_return),
                 (override));
     MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
@@ -56,7 +62,9 @@
                 (const std::shared_ptr<IHintSession>& hintSession, ::std::vector<int32_t>* tids),
                 (override));
     MOCK_METHOD(ScopedAStatus, getSessionChannel,
-                (const ::ndk::SpAIBinder& in_token, hal::ChannelConfig* _aidl_return), (override));
+                (const ::ndk::SpAIBinder& in_token,
+                 std::optional<hal::ChannelConfig>* _aidl_return),
+                (override));
     MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override));
     MOCK_METHOD(SpAIBinder, asBinder, (), (override));
     MOCK_METHOD(bool, isRemote, (), (override));
@@ -92,10 +100,12 @@
     }
 
     APerformanceHintManager* createManager() {
+        APerformanceHint_setUseFMQForTesting(mUsingFMQ);
         ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
                 .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); }));
         return APerformanceHint_getManager();
     }
+
     APerformanceHintSession* createSession(APerformanceHintManager* manager,
                                            int64_t targetDuration = 56789L, bool isHwui = false) {
         mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
@@ -106,8 +116,7 @@
 
         ON_CALL(*mMockIHintManager,
                 createHintSessionWithConfig(_, Eq(tids), Eq(targetDuration), _, _, _))
-                .WillByDefault(DoAll(SetArgPointee<4>(std::make_optional<hal::SessionConfig>(
-                                             {.id = sessionId})),
+                .WillByDefault(DoAll(SetArgPointee<4>(hal::SessionConfig({.id = sessionId})),
                                      SetArgPointee<5>(std::shared_ptr<IHintSession>(mMockSession)),
                                      [] { return ScopedAStatus::ok(); }));
 
@@ -133,8 +142,47 @@
         return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
     }
 
+    void setFMQEnabled(bool enabled) {
+        mUsingFMQ = enabled;
+        if (enabled) {
+            mMockFMQ = std::make_shared<
+                    AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>>(kMockQueueSize,
+                                                                                  true);
+            mMockFlagQueue =
+                    std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(1, true);
+            hardware::EventFlag::createEventFlag(mMockFlagQueue->getEventFlagWord(), &mEventFlag);
+
+            ON_CALL(*mMockIHintManager, getSessionChannel(_, _))
+                    .WillByDefault([&](ndk::SpAIBinder, std::optional<hal::ChannelConfig>* config) {
+                        config->emplace(
+                                hal::ChannelConfig{.channelDescriptor = mMockFMQ->dupeDesc(),
+                                                   .eventFlagDescriptor =
+                                                           mMockFlagQueue->dupeDesc(),
+                                                   .readFlagBitmask =
+                                                           static_cast<int32_t>(mReadBits),
+                                                   .writeFlagBitmask =
+                                                           static_cast<int32_t>(mWriteBits)});
+                        return ::ndk::ScopedAStatus::ok();
+                    });
+        }
+    }
+    uint32_t mReadBits = 0x00000001;
+    uint32_t mWriteBits = 0x00000002;
     std::shared_ptr<NiceMock<MockIHintManager>> mMockIHintManager = nullptr;
     std::shared_ptr<NiceMock<MockIHintSession>> mMockSession = nullptr;
+    std::shared_ptr<AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>> mMockFMQ;
+    std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mMockFlagQueue;
+    hardware::EventFlag* mEventFlag;
+    int kMockQueueSize = 20;
+    bool mUsingFMQ = false;
+
+    template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
+    void expectToReadFromFmq(C expected) {
+        hal::ChannelMessage readData;
+        mMockFMQ->readBlocking(&readData, 1, mReadBits, mWriteBits, 1000000000, mEventFlag);
+        C got = static_cast<C>(readData.data.get<T>());
+        ASSERT_EQ(got, expected);
+    }
 };
 
 bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) {
@@ -306,7 +354,7 @@
         actualWorkDurations.push_back(pair.duration);
 
         EXPECT_CALL(*mMockSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
-                .Times(Exactly(1));
+                .Times(Exactly(pair.expectedResult == OK));
         result = APerformanceHint_reportActualWorkDuration2(session,
                                                             reinterpret_cast<AWorkDuration*>(
                                                                     &pair.duration));
@@ -327,3 +375,48 @@
     AWorkDuration_setActualGpuDurationNanos(aWorkDuration, 8);
     AWorkDuration_release(aWorkDuration);
 }
+
+TEST_F(PerformanceHintTest, TestCreateUsingFMQ) {
+    setFMQEnabled(true);
+    APerformanceHintManager* manager = createManager();
+    APerformanceHintSession* session = createSession(manager);
+    ASSERT_TRUE(session);
+}
+
+TEST_F(PerformanceHintTest, TestUpdateTargetWorkDurationUsingFMQ) {
+    setFMQEnabled(true);
+    APerformanceHintManager* manager = createManager();
+    APerformanceHintSession* session = createSession(manager);
+    APerformanceHint_updateTargetWorkDuration(session, 456);
+    expectToReadFromFmq<HalChannelMessageContents::Tag::targetDuration>(456);
+}
+
+TEST_F(PerformanceHintTest, TestSendHintUsingFMQ) {
+    setFMQEnabled(true);
+    APerformanceHintManager* manager = createManager();
+    APerformanceHintSession* session = createSession(manager);
+    APerformanceHint_sendHint(session, SessionHint::CPU_LOAD_UP);
+    expectToReadFromFmq<HalChannelMessageContents::Tag::hint>(hal::SessionHint::CPU_LOAD_UP);
+}
+
+TEST_F(PerformanceHintTest, TestReportActualUsingFMQ) {
+    setFMQEnabled(true);
+    APerformanceHintManager* manager = createManager();
+    APerformanceHintSession* session = createSession(manager);
+    hal::WorkDuration duration{.timeStampNanos = 3,
+                               .durationNanos = 999999,
+                               .workPeriodStartTimestampNanos = 1,
+                               .cpuDurationNanos = 999999,
+                               .gpuDurationNanos = 999999};
+
+    hal::WorkDurationFixedV1 durationExpected{
+            .durationNanos = duration.durationNanos,
+            .workPeriodStartTimestampNanos = duration.workPeriodStartTimestampNanos,
+            .cpuDurationNanos = duration.cpuDurationNanos,
+            .gpuDurationNanos = duration.gpuDurationNanos,
+    };
+
+    APerformanceHint_reportActualWorkDuration2(session,
+                                               reinterpret_cast<AWorkDuration*>(&duration));
+    expectToReadFromFmq<HalChannelMessageContents::Tag::workDuration>(durationExpected);
+}
diff --git a/packages/SettingsLib/Graph/Android.bp b/packages/SettingsLib/Graph/Android.bp
index e2ed1e4..163b689 100644
--- a/packages/SettingsLib/Graph/Android.bp
+++ b/packages/SettingsLib/Graph/Android.bp
@@ -4,7 +4,7 @@
 
 filegroup {
     name: "SettingsLibGraph-srcs",
-    srcs: ["src/**/*"],
+    srcs: ["src/**/*.kt"],
 }
 
 android_library {
@@ -14,8 +14,24 @@
     ],
     srcs: [":SettingsLibGraph-srcs"],
     static_libs: [
+        "SettingsLibGraph-proto-lite",
+        "SettingsLibIpc",
+        "SettingsLibMetadata",
+        "SettingsLibPreference",
         "androidx.annotation_annotation",
+        "androidx.fragment_fragment",
         "androidx.preference_preference",
     ],
     kotlincflags: ["-Xjvm-default=all"],
 }
+
+java_library {
+    name: "SettingsLibGraph-proto-lite",
+    srcs: ["graph.proto"],
+    proto: {
+        type: "lite",
+        canonical_path_from_root: false,
+    },
+    sdk_version: "core_current",
+    static_libs: ["libprotobuf-java-lite"],
+}
diff --git a/packages/SettingsLib/Graph/graph.proto b/packages/SettingsLib/Graph/graph.proto
new file mode 100644
index 0000000..e93d756
--- /dev/null
+++ b/packages/SettingsLib/Graph/graph.proto
@@ -0,0 +1,156 @@
+syntax = "proto3";
+
+package com.android.settingslib.graph;
+
+option java_package = "com.android.settingslib.graph.proto";
+option java_multiple_files = true;
+
+// Proto represents preference graph.
+message PreferenceGraphProto {
+  // Preference screens appear in the graph.
+  // Key: preference key of the PreferenceScreen. Value: PreferenceScreen.
+  map<string, PreferenceScreenProto> screens = 1;
+  // Roots of the graph.
+  // Each element is a preference key of the PreferenceScreen.
+  repeated string roots = 2;
+  // Activities appear in the graph.
+  // Key: activity class. Value: preference key of associated PreferenceScreen.
+  map<string, string> activity_screens = 3;
+}
+
+// Proto of PreferenceScreen.
+message PreferenceScreenProto {
+  // Intent to show the PreferenceScreen.
+  optional IntentProto intent = 1;
+  // Root of the PreferenceScreen hierarchy.
+  optional PreferenceGroupProto root = 2;
+  // If the preference screen provides complete hierarchy by source code.
+  optional bool complete_hierarchy = 3;
+}
+
+// Proto of PreferenceGroup.
+message PreferenceGroupProto {
+  // Self information of PreferenceGroup.
+  optional PreferenceProto preference = 1;
+  // A list of children.
+  repeated PreferenceOrGroupProto preferences = 2;
+}
+
+// Proto represents either PreferenceProto or PreferenceGroupProto.
+message PreferenceOrGroupProto {
+  oneof kind {
+    // It is a Preference.
+    PreferenceProto preference = 1;
+    // It is a PreferenceGroup.
+    PreferenceGroupProto group = 2;
+  }
+}
+
+// Proto of Preference.
+message PreferenceProto {
+  // Key of the preference.
+  optional string key = 1;
+  // Title of the preference.
+  optional TextProto title = 2;
+  // Summary of the preference.
+  optional TextProto summary = 3;
+  // Icon of the preference.
+  optional int32 icon = 4;
+  // Additional keywords for indexing.
+  optional int32 keywords = 5;
+  // Extras of the preference.
+  optional BundleProto extras = 6;
+  // Whether the preference is indexable.
+  optional bool indexable = 7;
+  // Whether the preference is enabled.
+  optional bool enabled = 8;
+  // Whether the preference is available/visible.
+  optional bool available = 9;
+  // Whether the preference is persistent.
+  optional bool persistent = 10;
+  // Whether the preference is restricted by managed configurations.
+  optional bool restricted = 11;
+  // Target of the preference action.
+  optional ActionTarget action_target = 12;
+  // Preference value (if present, it means `persistent` is true).
+  optional PreferenceValueProto value = 13;
+
+  // Target of an Intent
+  message ActionTarget {
+    oneof kind {
+      // Resolved key of the preference screen located in current app.
+      // This is resolved from android:fragment or activity of current app.
+      string key = 1;
+      // Unresolvable Intent that is either an unrecognized activity of current
+      // app or activity belongs to other app.
+      IntentProto intent = 2;
+    }
+  }
+}
+
+// Proto of string or string resource id.
+message TextProto {
+  oneof text {
+    int32 resource_id = 1;
+    string string = 2;
+  }
+}
+
+// Proto of preference value.
+message PreferenceValueProto {
+  oneof value {
+    bool boolean_value = 1;
+  }
+}
+
+// Proto of android.content.Intent
+message IntentProto {
+  // The action of the Intent.
+  optional string action = 1;
+
+  // The data attribute of the Intent, expressed as a URI.
+  optional string data = 2;
+
+  // The package attribute of the Intent, which may be set to force the
+  // detection of a particular application package that can handle the event.
+  optional string pkg = 3;
+
+  // The component attribute of the Intent, which may be set to force the
+  // detection of a particular component (app). If present, this must be a
+  // package name followed by a '/' and then followed by the class name.
+  optional string component = 4;
+
+  // Flags controlling how intent is handled. The value must be bitwise OR of
+  // intent flag constants defined by Android.
+  // http://developer.android.com/reference/android/content/Intent.html#setFlags(int)
+  optional int32 flags = 5;
+
+  // Extended data from the intent.
+  optional BundleProto extras = 6;
+
+  // The MIME type of the Intent (e.g. "text/plain").
+  //
+  // For more information, see
+  // https://developer.android.com/reference/android/content/Intent#setType(java.lang.String).
+  optional string mime_type = 7;
+}
+
+// Proto of android.os.Bundle
+message BundleProto {
+  // Bundle data.
+  map<string, BundleValue> values = 1;
+
+  message BundleValue {
+    // Bundle data value for the associated key name.
+    // Can be extended to support other types of bundled data.
+    oneof value {
+      string string_value = 1;
+      bytes bytes_value = 2;
+      int32 int_value = 3;
+      int64 long_value = 4;
+      bool boolean_value = 5;
+      double double_value = 6;
+      BundleProto bundle_value = 7;
+    }
+  }
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
new file mode 100644
index 0000000..04c2968
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.graph
+
+import android.app.Application
+import android.os.Bundle
+import com.android.settingslib.graph.proto.PreferenceGraphProto
+import com.android.settingslib.ipc.ApiHandler
+import com.android.settingslib.ipc.MessageCodec
+import java.util.Locale
+
+/** API to get preference graph. */
+abstract class GetPreferenceGraphApiHandler(private val activityClasses: Set<String>) :
+    ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
+
+    override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
+        get() = GetPreferenceGraphRequestCodec
+
+    override val responseCodec: MessageCodec<PreferenceGraphProto>
+        get() = PreferenceGraphProtoCodec
+
+    override suspend fun invoke(
+        application: Application,
+        myUid: Int,
+        callingUid: Int,
+        request: GetPreferenceGraphRequest,
+    ): PreferenceGraphProto {
+        val builderRequest =
+            if (request.activityClasses.isEmpty()) {
+                GetPreferenceGraphRequest(activityClasses, request.visitedScreens, request.locale)
+            } else {
+                request
+            }
+        return PreferenceGraphBuilder.of(application, builderRequest).build()
+    }
+}
+
+/**
+ * Request of [GetPreferenceGraphApiHandler].
+ *
+ * @param activityClasses activities of the preference graph
+ * @param visitedScreens keys of the visited preference screen
+ * @param locale locale of the preference graph
+ */
+data class GetPreferenceGraphRequest
+@JvmOverloads
+constructor(
+    val activityClasses: Set<String> = setOf(),
+    val visitedScreens: Set<String> = setOf(),
+    val locale: Locale? = null,
+    val includeValue: Boolean = true,
+)
+
+object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> {
+    override fun encode(data: GetPreferenceGraphRequest): Bundle =
+        Bundle(3).apply {
+            putStringArray(KEY_ACTIVITIES, data.activityClasses.toTypedArray())
+            putStringArray(KEY_PREF_KEYS, data.visitedScreens.toTypedArray())
+            putString(KEY_LOCALE, data.locale?.toLanguageTag())
+        }
+
+    override fun decode(data: Bundle): GetPreferenceGraphRequest {
+        val activities = data.getStringArray(KEY_ACTIVITIES) ?: arrayOf()
+        val visitedScreens = data.getStringArray(KEY_PREF_KEYS) ?: arrayOf()
+        fun String?.toLocale() = if (this != null) Locale.forLanguageTag(this) else null
+        return GetPreferenceGraphRequest(
+            activities.toSet(),
+            visitedScreens.toSet(),
+            data.getString(KEY_LOCALE).toLocale(),
+        )
+    }
+
+    private const val KEY_ACTIVITIES = "activities"
+    private const val KEY_PREF_KEYS = "keys"
+    private const val KEY_LOCALE = "locale"
+}
+
+object PreferenceGraphProtoCodec : MessageCodec<PreferenceGraphProto> {
+    override fun encode(data: PreferenceGraphProto): Bundle =
+        Bundle(1).apply { putByteArray(KEY_GRAPH, data.toByteArray()) }
+
+    override fun decode(data: Bundle): PreferenceGraphProto =
+        PreferenceGraphProto.parseFrom(data.getByteArray(KEY_GRAPH)!!)
+
+    private const val KEY_GRAPH = "graph"
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
new file mode 100644
index 0000000..8c5d877
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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:Suppress("DEPRECATION")
+
+package com.android.settingslib.graph
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.res.Configuration
+import android.os.Build
+import android.os.Bundle
+import android.preference.PreferenceActivity
+import android.util.Log
+import androidx.fragment.app.Fragment
+import androidx.preference.Preference
+import androidx.preference.PreferenceGroup
+import androidx.preference.PreferenceScreen
+import androidx.preference.TwoStatePreference
+import com.android.settingslib.graph.proto.PreferenceGraphProto
+import com.android.settingslib.graph.proto.PreferenceGroupProto
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget
+import com.android.settingslib.graph.proto.PreferenceScreenProto
+import com.android.settingslib.graph.proto.TextProto
+import com.android.settingslib.metadata.BooleanValue
+import com.android.settingslib.metadata.PersistentPreference
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.PreferenceHierarchy
+import com.android.settingslib.metadata.PreferenceHierarchyNode
+import com.android.settingslib.metadata.PreferenceMetadata
+import com.android.settingslib.metadata.PreferenceRestrictionProvider
+import com.android.settingslib.metadata.PreferenceScreenBindingKeyProvider
+import com.android.settingslib.metadata.PreferenceScreenMetadata
+import com.android.settingslib.metadata.PreferenceScreenRegistry
+import com.android.settingslib.metadata.PreferenceSummaryProvider
+import com.android.settingslib.metadata.PreferenceTitleProvider
+import com.android.settingslib.preference.PreferenceScreenFactory
+import com.android.settingslib.preference.PreferenceScreenProvider
+import java.util.Locale
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+private const val TAG = "PreferenceGraphBuilder"
+
+/**
+ * Builder of preference graph.
+ *
+ * Only activity in current application is supported. To create preference graph across
+ * applications, use [crawlPreferenceGraph].
+ */
+class PreferenceGraphBuilder
+private constructor(private val context: Context, private val request: GetPreferenceGraphRequest) {
+    private val preferenceScreenFactory by lazy {
+        PreferenceScreenFactory(context.ofLocale(request.locale))
+    }
+    private val builder by lazy { PreferenceGraphProto.newBuilder() }
+    private val visitedScreens = mutableSetOf<String>().apply { addAll(request.visitedScreens) }
+    private val includeValue = request.includeValue
+
+    private suspend fun init() {
+        for (activityClass in request.activityClasses) {
+            add(activityClass)
+        }
+    }
+
+    fun build() = builder.build()
+
+    /** Adds an activity to the graph. */
+    suspend fun <T> add(activityClass: Class<T>) where T : Activity, T : PreferenceScreenProvider =
+        addPreferenceScreenProvider(activityClass)
+
+    /**
+     * Adds an activity to the graph.
+     *
+     * Reflection is used to create the instance. To avoid security vulnerability, the code ensures
+     * given [activityClassName] must be declared as an <activity> entry in AndroidManifest.xml.
+     */
+    suspend fun add(activityClassName: String) {
+        try {
+            val intent = Intent()
+            intent.setClassName(context, activityClassName)
+            if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) ==
+                null) {
+                Log.e(TAG, "$activityClassName is not activity")
+                return
+            }
+            val activityClass = context.classLoader.loadClass(activityClassName)
+            if (addPreferenceScreenKeyProvider(activityClass)) return
+            if (PreferenceScreenProvider::class.java.isAssignableFrom(activityClass)) {
+                addPreferenceScreenProvider(activityClass)
+            } else {
+                Log.w(TAG, "$activityClass does not implement PreferenceScreenProvider")
+            }
+        } catch (e: Exception) {
+            Log.e(TAG, "Fail to add $activityClassName", e)
+        }
+    }
+
+    private suspend fun addPreferenceScreenKeyProvider(activityClass: Class<*>): Boolean {
+        if (!PreferenceScreenBindingKeyProvider::class.java.isAssignableFrom(activityClass)) {
+            return false
+        }
+        val key = getPreferenceScreenKey { activityClass.newInstance() } ?: return false
+        if (addPreferenceScreenFromRegistry(key, activityClass)) {
+            builder.addRoots(key)
+            return true
+        }
+        return false
+    }
+
+    private suspend fun getPreferenceScreenKey(newInstance: () -> Any): String? =
+        withContext(Dispatchers.Main) {
+            try {
+                val instance = newInstance()
+                if (instance is PreferenceScreenBindingKeyProvider) {
+                    return@withContext instance.getPreferenceScreenBindingKey(context)
+                } else {
+                    Log.w(TAG, "$instance is not PreferenceScreenKeyProvider")
+                }
+            } catch (e: Exception) {
+                Log.e(TAG, "getPreferenceScreenKey failed", e)
+            }
+            null
+        }
+
+    private suspend fun addPreferenceScreenFromRegistry(
+        key: String,
+        activityClass: Class<*>,
+    ): Boolean {
+        val metadata = PreferenceScreenRegistry[key] ?: return false
+        if (!metadata.hasCompleteHierarchy()) return false
+        return addPreferenceScreenMetadata(metadata, activityClass)
+    }
+
+    private suspend fun addPreferenceScreenMetadata(
+        metadata: PreferenceScreenMetadata,
+        activityClass: Class<*>,
+    ): Boolean =
+        addPreferenceScreen(metadata.key, activityClass) {
+            preferenceScreenProto {
+                completeHierarchy = true
+                root = metadata.getPreferenceHierarchy(context).toProto(activityClass, true)
+            }
+        }
+
+    private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
+        Log.d(TAG, "add $activityClass")
+        createPreferenceScreen { activityClass.newInstance() }
+            ?.let {
+                addPreferenceScreen(Intent(context, activityClass), activityClass, it)
+                builder.addRoots(it.key)
+            }
+    }
+
+    /**
+     * Creates [PreferenceScreen].
+     *
+     * Androidx Activity/Fragment instance must be created in main thread, otherwise an exception is
+     * raised.
+     */
+    private suspend fun createPreferenceScreen(newInstance: () -> Any): PreferenceScreen? =
+        withContext(Dispatchers.Main) {
+            try {
+                val instance = newInstance()
+                Log.d(TAG, "createPreferenceScreen $instance")
+                if (instance is PreferenceScreenProvider) {
+                    return@withContext instance.createPreferenceScreen(preferenceScreenFactory)
+                } else {
+                    Log.w(TAG, "$instance is not PreferenceScreenProvider")
+                }
+            } catch (e: Exception) {
+                Log.e(TAG, "createPreferenceScreen failed", e)
+            }
+            return@withContext null
+        }
+
+    private suspend fun addPreferenceScreen(
+        intent: Intent,
+        activityClass: Class<*>,
+        preferenceScreen: PreferenceScreen?,
+    ) {
+        val key = preferenceScreen?.key
+        if (key.isNullOrEmpty()) {
+            Log.e(TAG, "$activityClass \"$preferenceScreen\" has no key")
+            return
+        }
+        @Suppress("CheckReturnValue")
+        addPreferenceScreen(key, activityClass) { preferenceScreen.toProto(intent, activityClass) }
+    }
+
+    private suspend fun addPreferenceScreen(
+        key: String,
+        activityClass: Class<*>,
+        preferenceScreenProvider: suspend () -> PreferenceScreenProto,
+    ): Boolean {
+        if (!visitedScreens.add(key)) {
+            Log.w(TAG, "$activityClass $key visited")
+            return false
+        }
+        val activityClassName = activityClass.name
+        val associatedKey = builder.getActivityScreensOrDefault(activityClassName, null)
+        if (associatedKey == null) {
+            builder.putActivityScreens(activityClassName, key)
+        } else if (associatedKey != key) {
+            Log.w(TAG, "Dup $activityClassName association, old: $associatedKey, new: $key")
+        }
+        builder.putScreens(key, preferenceScreenProvider())
+        return true
+    }
+
+    private suspend fun PreferenceScreen.toProto(
+        intent: Intent,
+        activityClass: Class<*>,
+    ): PreferenceScreenProto = preferenceScreenProto {
+        this.intent = intent.toProto()
+        root = (this@toProto as PreferenceGroup).toProto(activityClass)
+    }
+
+    private suspend fun PreferenceGroup.toProto(activityClass: Class<*>): PreferenceGroupProto =
+        preferenceGroupProto {
+            preference = (this@toProto as Preference).toProto(activityClass)
+            for (index in 0 until preferenceCount) {
+                val child = getPreference(index)
+                addPreferences(
+                    preferenceOrGroupProto {
+                        if (child is PreferenceGroup) {
+                            group = child.toProto(activityClass)
+                        } else {
+                            preference = child.toProto(activityClass)
+                        }
+                    })
+            }
+        }
+
+    private suspend fun Preference.toProto(activityClass: Class<*>): PreferenceProto =
+        preferenceProto {
+            this@toProto.key?.let { key = it }
+            this@toProto.title?.let { title = textProto { string = it.toString() } }
+            this@toProto.summary?.let { summary = textProto { string = it.toString() } }
+            val preferenceExtras = peekExtras()
+            preferenceExtras?.let { extras = it.toProto() }
+            enabled = isEnabled
+            available = isVisible
+            persistent = isPersistent
+            if (includeValue && isPersistent && this@toProto is TwoStatePreference) {
+                value = preferenceValueProto { booleanValue = this@toProto.isChecked }
+            }
+            this@toProto.fragment.toActionTarget(activityClass, preferenceExtras)?.let {
+                actionTarget = it
+                return@preferenceProto
+            }
+            this@toProto.intent?.let { actionTarget = it.toActionTarget() }
+        }
+
+    private suspend fun PreferenceHierarchy.toProto(
+        activityClass: Class<*>,
+        isRoot: Boolean,
+    ): PreferenceGroupProto = preferenceGroupProto {
+        preference = toProto(this@toProto, activityClass, isRoot)
+        forEachAsync {
+            addPreferences(
+                preferenceOrGroupProto {
+                    if (it is PreferenceHierarchy) {
+                        group = it.toProto(activityClass, false)
+                    } else {
+                        preference = toProto(it, activityClass, false)
+                    }
+                })
+        }
+    }
+
+    private suspend fun toProto(
+        node: PreferenceHierarchyNode,
+        activityClass: Class<*>,
+        isRoot: Boolean,
+    ) = preferenceProto {
+        val metadata = node.metadata
+        key = metadata.key
+        metadata.getTitleTextProto(isRoot)?.let { title = it }
+        if (metadata.summary != 0) {
+            summary = textProto { resourceId = metadata.summary }
+        } else {
+            (metadata as? PreferenceSummaryProvider)?.getSummary(context)?.let {
+                summary = textProto { string = it.toString() }
+            }
+        }
+        if (metadata.icon != 0) icon = metadata.icon
+        if (metadata.keywords != 0) keywords = metadata.keywords
+        val preferenceExtras = metadata.extras(context)
+        preferenceExtras?.let { extras = it.toProto() }
+        indexable = metadata.isIndexable(context)
+        enabled = metadata.isEnabled(context)
+        if (metadata is PreferenceAvailabilityProvider) {
+            available = metadata.isAvailable(context)
+        }
+        if (metadata is PreferenceRestrictionProvider) {
+            restricted = metadata.isRestricted(context)
+        }
+        persistent = metadata.isPersistent(context)
+        if (includeValue &&
+            persistent &&
+            metadata is BooleanValue &&
+            metadata is PersistentPreference<*>) {
+            metadata.storage(context).getValue(metadata.key, Boolean::class.javaObjectType)?.let {
+                value = preferenceValueProto { booleanValue = it }
+            }
+        }
+        if (metadata is PreferenceScreenMetadata) {
+            if (metadata.hasCompleteHierarchy()) {
+                @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata, activityClass)
+            } else {
+                metadata.fragmentClass()?.toActionTarget(activityClass, preferenceExtras)?.let {
+                    actionTarget = it
+                }
+            }
+        }
+        metadata.intent(context)?.let { actionTarget = it.toActionTarget() }
+    }
+
+    private fun PreferenceMetadata.getTitleTextProto(isRoot: Boolean): TextProto? {
+        if (isRoot && this is PreferenceScreenMetadata) {
+            val titleRes = screenTitle
+            if (titleRes != 0) {
+                return textProto { resourceId = titleRes }
+            } else {
+                getScreenTitle(context)?.let {
+                    return textProto { string = it.toString() }
+                }
+            }
+        } else {
+            val titleRes = title
+            if (titleRes != 0) {
+                return textProto { resourceId = titleRes }
+            }
+        }
+        return (this as? PreferenceTitleProvider)?.getTitle(context)?.let {
+            textProto { string = it.toString() }
+        }
+    }
+
+    private suspend fun String?.toActionTarget(
+        activityClass: Class<*>,
+        extras: Bundle?,
+    ): ActionTarget? {
+        if (this.isNullOrEmpty()) return null
+        try {
+            val fragmentClass = context.classLoader.loadClass(this)
+            if (Fragment::class.java.isAssignableFrom(fragmentClass)) {
+                @Suppress("UNCHECKED_CAST")
+                return (fragmentClass as Class<out Fragment>).toActionTarget(activityClass, extras)
+            }
+        } catch (e: Exception) {
+            Log.e(TAG, "Cannot loadClass $this", e)
+        }
+        return null
+    }
+
+    private suspend fun Class<out Fragment>.toActionTarget(
+        activityClass: Class<*>,
+        extras: Bundle?,
+    ): ActionTarget {
+        val startIntent = Intent(context, activityClass)
+        startIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, name)
+        extras?.let { startIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, it) }
+        if (!PreferenceScreenProvider::class.java.isAssignableFrom(this) &&
+            !PreferenceScreenBindingKeyProvider::class.java.isAssignableFrom(this)) {
+            return actionTargetProto { intent = startIntent.toProto() }
+        }
+        val fragment =
+            withContext(Dispatchers.Main) {
+                return@withContext try {
+                    newInstance().apply { arguments = extras }
+                } catch (e: Exception) {
+                    Log.e(TAG, "Fail to instantiate fragment ${this@toActionTarget}", e)
+                    null
+                }
+            }
+        if (fragment is PreferenceScreenBindingKeyProvider) {
+            val screenKey = fragment.getPreferenceScreenBindingKey(context)
+            if (screenKey != null && addPreferenceScreenFromRegistry(screenKey, activityClass)) {
+                return actionTargetProto { key = screenKey }
+            }
+        }
+        if (fragment is PreferenceScreenProvider) {
+            val screen = fragment.createPreferenceScreen(preferenceScreenFactory)
+            if (screen != null) {
+                addPreferenceScreen(startIntent, activityClass, screen)
+                return actionTargetProto { key = screen.key }
+            }
+        }
+        return actionTargetProto { intent = startIntent.toProto() }
+    }
+
+    private suspend fun Intent.toActionTarget(): ActionTarget {
+        if (component?.packageName == "") {
+            setClassName(context, component!!.className)
+        }
+        resolveActivity(context.packageManager)?.let {
+            if (it.packageName == context.packageName) {
+                add(it.className)
+            }
+        }
+        return actionTargetProto { intent = toProto() }
+    }
+
+    companion object {
+        suspend fun of(context: Context, request: GetPreferenceGraphRequest) =
+            PreferenceGraphBuilder(context, request).also { it.init() }
+    }
+}
+
+@SuppressLint("AppBundleLocaleChanges")
+internal fun Context.ofLocale(locale: Locale?): Context {
+    if (locale == null) return this
+    val baseConfig: Configuration = resources.configuration
+    val baseLocale =
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            baseConfig.locales[0]
+        } else {
+            baseConfig.locale
+        }
+    if (locale == baseLocale) {
+        return this
+    }
+    val newConfig = Configuration(baseConfig)
+    newConfig.setLocale(locale)
+    return createConfigurationContext(newConfig)
+}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenManager.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenManager.kt
deleted file mode 100644
index 9231f40..0000000
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenManager.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.android.settingslib.graph
-
-import androidx.annotation.StringRes
-import androidx.annotation.XmlRes
-import androidx.preference.Preference
-import androidx.preference.PreferenceManager
-import androidx.preference.PreferenceScreen
-
-/** Manager to create and initialize preference screen. */
-class PreferenceScreenManager(private val preferenceManager: PreferenceManager) {
-    private val context = preferenceManager.context
-    // the map will preserve order
-    private val updaters = mutableMapOf<String, PreferenceUpdater>()
-    private val screenUpdaters = mutableListOf<PreferenceScreenUpdater>()
-
-    /** Creates an empty [PreferenceScreen]. */
-    fun createPreferenceScreen(): PreferenceScreen =
-        preferenceManager.createPreferenceScreen(context)
-
-    /** Creates [PreferenceScreen] from resource. */
-    fun createPreferenceScreen(@XmlRes xmlRes: Int): PreferenceScreen =
-        preferenceManager.inflateFromResource(context, xmlRes, null)
-
-    /** Adds updater for given preference. */
-    fun addPreferenceUpdater(@StringRes key: Int, updater: PreferenceUpdater) =
-        addPreferenceUpdater(context.getString(key), updater)
-
-    /** Adds updater for given preference. */
-    fun addPreferenceUpdater(
-        key: String,
-        updater: PreferenceUpdater,
-    ): PreferenceScreenManager {
-        updaters.put(key, updater)?.let { if (it != updater) throw IllegalArgumentException() }
-        return this
-    }
-
-    /** Adds updater for preference screen. */
-    fun addPreferenceScreenUpdater(updater: PreferenceScreenUpdater): PreferenceScreenManager {
-        screenUpdaters.add(updater)
-        return this
-    }
-
-    /** Adds a list of updaters for preference screen. */
-    fun addPreferenceScreenUpdater(
-        vararg updaters: PreferenceScreenUpdater,
-    ): PreferenceScreenManager {
-        screenUpdaters.addAll(updaters)
-        return this
-    }
-
-    /** Updates preference screen with registered updaters. */
-    fun updatePreferenceScreen(preferenceScreen: PreferenceScreen) {
-        for ((key, updater) in updaters) {
-            preferenceScreen.findPreference<Preference>(key)?.let { updater.updatePreference(it) }
-        }
-        for (updater in screenUpdaters) {
-            updater.updatePreferenceScreen(preferenceScreen)
-        }
-    }
-}
-
-/** Updater of [Preference]. */
-interface PreferenceUpdater {
-    fun updatePreference(preference: Preference)
-}
-
-/** Updater of [PreferenceScreen]. */
-interface PreferenceScreenUpdater {
-    fun updatePreferenceScreen(preferenceScreen: PreferenceScreen)
-}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenProvider.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenProvider.kt
deleted file mode 100644
index 9e4c1f6..0000000
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceScreenProvider.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.android.settingslib.graph
-
-import android.content.Context
-import androidx.preference.PreferenceScreen
-
-/**
- * Interface to provide [PreferenceScreen].
- *
- * It is expected to be implemented by Activity/Fragment and the implementation needs to use
- * [Context] APIs (e.g. `getContext()`, `getActivity()`) with caution: preference screen creation
- * could happen in background service, where the Activity/Fragment lifecycle callbacks (`onCreate`,
- * `onDestroy`, etc.) are not invoked.
- */
-interface PreferenceScreenProvider {
-
-    /**
-     * Creates [PreferenceScreen].
-     *
-     * Preference screen creation could happen in background service. The implementation MUST use
-     * given [context] instead of APIs like `getContext()`, `getActivity()`, etc.
-     */
-    fun createPreferenceScreen(
-        context: Context,
-        preferenceScreenManager: PreferenceScreenManager,
-    ): PreferenceScreen?
-}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
new file mode 100644
index 0000000..d9b9590
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.graph
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.android.settingslib.graph.proto.BundleProto
+import com.android.settingslib.graph.proto.BundleProto.BundleValue
+import com.android.settingslib.graph.proto.IntentProto
+import com.android.settingslib.graph.proto.TextProto
+import com.google.protobuf.ByteString
+
+fun TextProto.getText(context: Context): String? =
+    when {
+        hasResourceId() -> context.getString(resourceId)
+        hasString() -> string
+        else -> null
+    }
+
+fun Intent.toProto(): IntentProto = intentProto {
+    this@toProto.action?.let { action = it }
+    this@toProto.dataString?.let { data = it }
+    this@toProto.`package`?.let { pkg = it }
+    this@toProto.component?.let { component = it.flattenToShortString() }
+    this@toProto.flags.let { if (it != 0) flags = it }
+    this@toProto.extras?.let { extras = it.toProto() }
+    this@toProto.type?.let { mimeType = it }
+}
+
+fun Bundle.toProto(): BundleProto = bundleProto {
+    fun toProto(value: Any): BundleValue = bundleValueProto {
+        when (value) {
+            is String -> stringValue = value
+            is ByteArray -> bytesValue = ByteString.copyFrom(value)
+            is Int -> intValue = value
+            is Long -> longValue = value
+            is Boolean -> booleanValue = value
+            is Double -> doubleValue = value
+            is Bundle -> bundleValue = value.toProto()
+            else -> throw IllegalArgumentException("Unknown type: ${value.javaClass} $value")
+        }
+    }
+
+    for (key in keySet()) {
+        @Suppress("DEPRECATION") get(key)?.let { putValues(key, toProto(it)) }
+    }
+}
+
+fun BundleValue.stringify(): String =
+    when {
+        hasBooleanValue() -> "$valueCase"
+        hasBytesValue() -> "$bytesValue"
+        hasIntValue() -> "$intValue"
+        hasLongValue() -> "$longValue"
+        hasStringValue() -> stringValue
+        hasDoubleValue() -> "$doubleValue"
+        hasBundleValue() -> "$bundleValue"
+        else -> "Unknown"
+    }
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.kt
new file mode 100644
index 0000000..d7dae77
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoDsl.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.graph
+
+import com.android.settingslib.graph.proto.BundleProto
+import com.android.settingslib.graph.proto.BundleProto.BundleValue
+import com.android.settingslib.graph.proto.IntentProto
+import com.android.settingslib.graph.proto.PreferenceGroupProto
+import com.android.settingslib.graph.proto.PreferenceOrGroupProto
+import com.android.settingslib.graph.proto.PreferenceProto
+import com.android.settingslib.graph.proto.PreferenceProto.ActionTarget
+import com.android.settingslib.graph.proto.PreferenceScreenProto
+import com.android.settingslib.graph.proto.PreferenceValueProto
+import com.android.settingslib.graph.proto.TextProto
+
+/** Returns root or null. */
+val PreferenceScreenProto.rootOrNull
+    get() = if (hasRoot()) root else null
+
+/** Kotlin DSL-style builder for [PreferenceScreenProto]. */
+@JvmSynthetic
+inline fun preferenceScreenProto(init: PreferenceScreenProto.Builder.() -> Unit) =
+    PreferenceScreenProto.newBuilder().also(init).build()
+
+/** Returns preference or null. */
+val PreferenceOrGroupProto.preferenceOrNull
+    get() = if (hasPreference()) preference else null
+
+/** Returns group or null. */
+val PreferenceOrGroupProto.groupOrNull
+    get() = if (hasGroup()) group else null
+
+/** Kotlin DSL-style builder for [PreferenceOrGroupProto]. */
+@JvmSynthetic
+inline fun preferenceOrGroupProto(init: PreferenceOrGroupProto.Builder.() -> Unit) =
+    PreferenceOrGroupProto.newBuilder().also(init).build()
+
+/** Returns preference or null. */
+val PreferenceGroupProto.preferenceOrNull
+    get() = if (hasPreference()) preference else null
+
+/** Kotlin DSL-style builder for [PreferenceGroupProto]. */
+@JvmSynthetic
+inline fun preferenceGroupProto(init: PreferenceGroupProto.Builder.() -> Unit) =
+    PreferenceGroupProto.newBuilder().also(init).build()
+
+/** Returns title or null. */
+val PreferenceProto.titleOrNull
+    get() = if (hasTitle()) title else null
+
+/** Returns summary or null. */
+val PreferenceProto.summaryOrNull
+    get() = if (hasSummary()) summary else null
+
+/** Returns actionTarget or null. */
+val PreferenceProto.actionTargetOrNull
+    get() = if (hasActionTarget()) actionTarget else null
+
+/** Kotlin DSL-style builder for [PreferenceProto]. */
+@JvmSynthetic
+inline fun preferenceProto(init: PreferenceProto.Builder.() -> Unit) =
+    PreferenceProto.newBuilder().also(init).build()
+
+/** Returns intent or null. */
+val ActionTarget.intentOrNull
+    get() = if (hasIntent()) intent else null
+
+/** Kotlin DSL-style builder for [ActionTarget]. */
+@JvmSynthetic
+inline fun actionTargetProto(init: ActionTarget.Builder.() -> Unit) =
+    ActionTarget.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [PreferenceValueProto]. */
+@JvmSynthetic
+inline fun preferenceValueProto(init: PreferenceValueProto.Builder.() -> Unit) =
+    PreferenceValueProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [TextProto]. */
+@JvmSynthetic
+inline fun textProto(init: TextProto.Builder.() -> Unit) = TextProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [IntentProto]. */
+@JvmSynthetic
+inline fun intentProto(init: IntentProto.Builder.() -> Unit) =
+    IntentProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [BundleProto]. */
+@JvmSynthetic
+inline fun bundleProto(init: BundleProto.Builder.() -> Unit) =
+    BundleProto.newBuilder().also(init).build()
+
+/** Kotlin DSL-style builder for [BundleValue]. */
+@JvmSynthetic
+inline fun bundleValueProto(init: BundleValue.Builder.() -> Unit) =
+    BundleValue.newBuilder().also(init).build()
diff --git a/packages/SettingsLib/Ipc/Android.bp b/packages/SettingsLib/Ipc/Android.bp
new file mode 100644
index 0000000..2c7209a
--- /dev/null
+++ b/packages/SettingsLib/Ipc/Android.bp
@@ -0,0 +1,34 @@
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "SettingsLibIpc-srcs",
+    srcs: ["src/**/*.kt"],
+}
+
+android_library {
+    name: "SettingsLibIpc",
+    defaults: [
+        "SettingsLintDefaults",
+    ],
+    srcs: [":SettingsLibIpc-srcs"],
+    static_libs: [
+        "androidx.collection_collection",
+        "guava",
+        "kotlinx-coroutines-android",
+    ],
+    kotlincflags: ["-Xjvm-default=all"],
+}
+
+android_library {
+    name: "SettingsLibIpc-testutils",
+    srcs: ["testutils/**/*.kt"],
+    static_libs: [
+        "Robolectric_all-target_upstream",
+        "SettingsLibIpc",
+        "androidx.test.core",
+        "flag-junit",
+        "kotlinx-coroutines-android",
+    ],
+}
diff --git a/packages/SettingsLib/Ipc/AndroidManifest.xml b/packages/SettingsLib/Ipc/AndroidManifest.xml
new file mode 100644
index 0000000..fc48a7d
--- /dev/null
+++ b/packages/SettingsLib/Ipc/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.ipc">
+
+    <uses-sdk android:minSdkVersion="21" />
+</manifest>
diff --git a/packages/SettingsLib/Ipc/README.md b/packages/SettingsLib/Ipc/README.md
new file mode 100644
index 0000000..ea2c3a1b5
--- /dev/null
+++ b/packages/SettingsLib/Ipc/README.md
@@ -0,0 +1,116 @@
+# Service IPC library
+
+This library provides a kind of IPC (inter-process communication) framework
+based on Android
+[bound service](https://developer.android.com/develop/background-work/services/bound-services)
+with [Messenger](https://developer.android.com/reference/android/os/Messenger).
+
+Following benefits are offered by the library to improve and simplify IPC
+development:
+
+-   Enforce permission check for every API implementation to avoid security
+    vulnerability.
+-   Allow modular API development for better code maintenance (no more huge
+    Service class).
+-   Prevent common mistakes, e.g. Service context leaking, ServiceConnection
+    management.
+
+## Overview
+
+In this manner of IPC,
+[Service](https://developer.android.com/reference/android/app/Service) works
+with [Handler](https://developer.android.com/reference/android/os/Handler) to
+deal with different types of
+[Message](https://developer.android.com/reference/android/os/Message) objects.
+
+Under the hood, each API is represented as a `Message` object:
+
+-   [what](https://developer.android.com/reference/android/os/Message#what):
+    used to identify API.
+-   [data](https://developer.android.com/reference/android/os/Message#getData\(\)):
+    payload of the API parameters and result.
+
+This could be mapped to the `ApiHandler` interface abstraction exactly.
+Specifically, the API implementation needs to provide:
+
+-   An unique id for the API.
+-   How to marshall/unmarshall the request and response.
+-   Whether the given request is permitted.
+
+## Threading model
+
+`MessengerService` starts a dedicated
+[HandlerThread](https://developer.android.com/reference/android/os/HandlerThread)
+to handle requests. `ApiHandler` implementation uses Kotlin `suspend`, which
+allows flexible threading model on top of the
+[Kotlin coroutines](https://kotlinlang.org/docs/coroutines-overview.html).
+
+## Usage
+
+The service provider should extend `MessengerService` and provide API
+implementations. In `AndroidManifest.xml`, declare `<service>` with permission,
+intent filter, etc. if needed.
+
+Meanwhile, the service client implements `MessengerServiceClient` with API
+descriptors to make requests.
+
+Here is an example:
+
+```kotlin
+import android.app.Application
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import kotlinx.coroutines.runBlocking
+
+class EchoService :
+  MessengerService(
+    listOf(EchoApiImpl),
+    PermissionChecker { _, _, _ -> true },
+  )
+
+class EchoServiceClient(context: Context) : MessengerServiceClient(context) {
+  override val serviceIntentFactory: () -> Intent
+    get() = { Intent("example.intent.action.ECHO") }
+
+  fun echo(data: String?): String? =
+    runBlocking { invoke(context.packageName, EchoApi, data).await() }
+}
+
+object EchoApi : ApiDescriptor<String?, String?> {
+  private val codec =
+    object : MessageCodec<String?> {
+      override fun encode(data: String?) =
+        Bundle(1).apply { putString("data", data) }
+
+      override fun decode(data: Bundle): String? = data.getString("data", null)
+    }
+
+  override val id: Int
+    get() = 1
+
+  override val requestCodec: MessageCodec<String?>
+    get() = codec
+
+  override val responseCodec: MessageCodec<String?>
+    get() = codec
+}
+
+// This is not needed by EchoServiceClient.
+object EchoApiImpl : ApiHandler<String?, String?>,
+                     ApiDescriptor<String?, String?> by EchoApi {
+  override suspend fun invoke(
+    application: Application,
+    myUid: Int,
+    callingUid: Int,
+    request: String?,
+  ): String? = request
+
+  override fun hasPermission(
+    application: Application,
+    myUid: Int,
+    callingUid: Int,
+    request: String?,
+  ): Boolean = (request?.length ?: 0) <= 5
+}
+```
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiException.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiException.kt
new file mode 100644
index 0000000..42772a4
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiException.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ipc
+
+/** Exception raised when handle request. */
+sealed class ApiException : Exception {
+    constructor() : super()
+
+    constructor(cause: Throwable?) : super(cause)
+
+    constructor(message: String, cause: Throwable?) : super(message, cause)
+}
+
+/** Exception occurred on client side. */
+open class ApiClientException : ApiException {
+    constructor() : super()
+
+    constructor(cause: Throwable?) : super(cause)
+
+    constructor(message: String, cause: Throwable?) : super(message, cause)
+}
+
+/** Client has already been closed. */
+class ClientClosedException : ApiClientException()
+
+/** Api to request is invalid, e.g. negative identity number. */
+class ClientInvalidApiException(message: String) : ApiClientException(message, null)
+
+/**
+ * Exception when bind service failed.
+ *
+ * This exception may be raised for following reasons:
+ * - Context used to bind service has finished its lifecycle (e.g. activity stopped).
+ * - Service not found.
+ * - Permission denied.
+ */
+class ClientBindServiceException(cause: Throwable?) : ApiClientException(cause)
+
+/** Exception when encode request. */
+class ClientEncodeException(cause: Throwable) : ApiClientException(cause)
+
+/** Exception when decode response. */
+class ClientDecodeException(cause: Throwable) : ApiClientException(cause)
+
+/** Exception when send message. */
+class ClientSendException(message: String, cause: Throwable) : ApiClientException(message, cause)
+
+/** Service returns unknown error code. */
+class ClientUnknownResponseCodeException(code: Int) :
+    ApiClientException("Unknown code: $code", null)
+
+/** Exception returned from service. */
+open class ApiServiceException : ApiException() {
+    companion object {
+        internal const val CODE_OK = 0
+        internal const val CODE_PERMISSION_DENIED = 1
+        internal const val CODE_UNKNOWN_API = 2
+        internal const val CODE_INTERNAL_ERROR = 3
+
+        internal fun of(code: Int): ApiServiceException? =
+            when (code) {
+                CODE_PERMISSION_DENIED -> ServicePermissionDeniedException()
+                CODE_UNKNOWN_API -> ServiceUnknownApiException()
+                CODE_INTERNAL_ERROR -> ServiceInternalException()
+                else -> null
+            }
+    }
+}
+
+/** Exception indicates the request is rejected due to permission deny. */
+class ServicePermissionDeniedException : ApiServiceException()
+
+/** Exception indicates API request is unknown. */
+class ServiceUnknownApiException : ApiServiceException()
+
+/** Exception indicates internal issue occurred when service handles the request. */
+class ServiceInternalException : ApiServiceException()
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt
new file mode 100644
index 0000000..802141d
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.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.settingslib.ipc
+
+import android.app.Application
+import android.os.Bundle
+
+/**
+ * Codec to marshall/unmarshall data between given type and [Bundle].
+ *
+ * The implementation must be threadsafe and stateless.
+ */
+interface MessageCodec<T> {
+    /** Converts given data to [Bundle]. */
+    fun encode(data: T): Bundle
+
+    /** Converts [Bundle] to an object of given data type. */
+    fun decode(data: Bundle): T
+}
+
+/**
+ * Descriptor of API.
+ *
+ * Used by both [MessengerService] and [MessengerServiceClient] to identify API and encode/decode
+ * messages.
+ */
+interface ApiDescriptor<Request, Response> {
+    /**
+     * Identity of the API.
+     *
+     * The id must be:
+     * - Positive: the negative numbers are reserved for internal messages.
+     * - Unique within the [MessengerService].
+     * - Permanent to achieve backward compatibility.
+     */
+    val id: Int
+
+    /** Codec for request. */
+    val requestCodec: MessageCodec<Request>
+
+    /** Codec for response. */
+    val responseCodec: MessageCodec<Response>
+}
+
+/**
+ * Handler of API.
+ *
+ * This is the API implementation portion, which is used by [MessengerService] only.
+ * [MessengerServiceClient] does NOT need this interface at all to make request.
+ *
+ * The implementation must be threadsafe.
+ */
+interface ApiHandler<Request, Response> : ApiDescriptor<Request, Response> {
+    /**
+     * Returns if the request is permitted.
+     *
+     * @return `false` if permission is denied, otherwise `true`
+     */
+    fun hasPermission(
+        application: Application,
+        myUid: Int,
+        callingUid: Int,
+        request: Request,
+    ): Boolean
+
+    /**
+     * Invokes the API.
+     *
+     * The API is invoked from Service handler thread, do not perform time-consuming task. Start
+     * coroutine in another thread if it takes time to complete.
+     */
+    suspend fun invoke(
+        application: Application,
+        myUid: Int,
+        callingUid: Int,
+        request: Request,
+    ): Response
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessageCodecs.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessageCodecs.kt
new file mode 100644
index 0000000..4b7572b
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessageCodecs.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.ipc
+
+import android.os.Bundle
+
+/** [MessageCodec] for [Int]. */
+object IntMessageCodec : MessageCodec<Int> {
+    override fun encode(data: Int): Bundle = Bundle(1).apply { putInt(null, data) }
+
+    override fun decode(data: Bundle): Int = data.getInt(null)
+}
+
+/** [MessageCodec] for [Set<Int>]. */
+class IntSetMessageCodec : MessageCodec<Set<Int>> {
+    override fun encode(data: Set<Int>): Bundle =
+        Bundle(1).apply { putIntArray(null, data.toIntArray()) }
+
+    override fun decode(data: Bundle): Set<Int> = data.getIntArray(null)?.toSet() ?: setOf()
+}
+
+/** [MessageCodec] for [Set<String>]. */
+class StringSetMessageCodec : MessageCodec<Set<String>> {
+    override fun encode(data: Set<String>): Bundle =
+        Bundle(1).apply { putStringArray(null, data.toTypedArray()) }
+
+    override fun decode(data: Bundle): Set<String> = data.getStringArray(null)?.toSet() ?: setOf()
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerService.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerService.kt
new file mode 100644
index 0000000..0bdae38
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerService.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ipc
+
+import android.app.Application
+import android.app.Service
+import android.content.Intent
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.IBinder
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
+import android.os.Process
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+
+/**
+ * [Messenger] based bound service for IPC.
+ *
+ * A dedicated [HandlerThread] is created to handle all requests.
+ *
+ * @param apiHandlers API handlers associated with the service
+ * @param permissionChecker Checker for permission
+ * @param name name of the handler thread
+ */
+open class MessengerService(
+    private val apiHandlers: List<ApiHandler<*, *>>,
+    private val permissionChecker: PermissionChecker,
+    name: String = TAG,
+) : Service() {
+    @VisibleForTesting internal val handlerThread = HandlerThread(name)
+    @VisibleForTesting internal lateinit var handler: IncomingHandler
+    private lateinit var messenger: Messenger
+
+    override fun onCreate() {
+        super.onCreate()
+        handlerThread.start()
+        handler =
+            IncomingHandler(
+                handlerThread.looper,
+                applicationContext as Application,
+                apiHandlers.toSortedArray(),
+                permissionChecker,
+            )
+        messenger = Messenger(handler)
+        Log.i(TAG, "onCreate HandlerThread ${handlerThread.threadId}")
+    }
+
+    override fun onBind(intent: Intent): IBinder? {
+        // this method is executed only once even there is more than 1 client
+        Log.i(TAG, "onBind $intent")
+        return messenger.binder
+    }
+
+    override fun onUnbind(intent: Intent): Boolean {
+        // invoked when ALL clients are unbound
+        Log.i(TAG, "onUnbind $intent")
+        handler.coroutineScope.cancel()
+        return super.onUnbind(intent)
+    }
+
+    override fun onDestroy() {
+        Log.i(TAG, "onDestroy HandlerThread ${handlerThread.threadId}")
+        handlerThread.quitSafely()
+        super.onDestroy()
+    }
+
+    @VisibleForTesting
+    internal class IncomingHandler(
+        looper: Looper,
+        private val application: Application,
+        private val apiHandlers: Array<ApiHandler<*, *>>,
+        private val permissionChecker: PermissionChecker,
+    ) : Handler(looper) {
+        @VisibleForTesting internal val myUid = Process.myUid()
+        val coroutineScope = CoroutineScope(asCoroutineDispatcher().immediate + SupervisorJob())
+
+        override fun handleMessage(msg: Message) {
+            coroutineScope.launch { handle(msg) }
+        }
+
+        @VisibleForTesting
+        internal suspend fun handle(msg: Message) {
+            Log.d(TAG, "receive request $msg")
+            val replyTo = msg.replyTo
+            if (replyTo == null) {
+                Log.e(TAG, "Ignore msg without replyTo: $msg")
+                return
+            }
+            val apiId = msg.what
+            val txnId = msg.arg1
+            val callingUid = msg.sendingUid
+            val data = msg.data
+            // WARNING: never access "msg" beyond this point as it may be recycled by Looper
+            val response = Message.obtain(null, apiId, txnId, ApiServiceException.CODE_OK)
+            try {
+                if (permissionChecker.check(application, myUid, callingUid)) {
+                    @Suppress("UNCHECKED_CAST")
+                    val apiHandler = findApiHandler(apiId) as? ApiHandler<Any, Any>
+                    if (apiHandler != null) {
+                        val request = apiHandler.requestCodec.decode(data)
+                        if (apiHandler.hasPermission(application, myUid, callingUid, request)) {
+                            val result = apiHandler.invoke(application, myUid, callingUid, request)
+                            response.data = apiHandler.responseCodec.encode(result)
+                        } else {
+                            response.arg2 = ApiServiceException.CODE_PERMISSION_DENIED
+                        }
+                    } else {
+                        response.arg2 = ApiServiceException.CODE_UNKNOWN_API
+                        Log.e(TAG, "Unknown request [txnId=$txnId,apiId=$apiId]")
+                    }
+                } else {
+                    response.arg2 = ApiServiceException.CODE_PERMISSION_DENIED
+                }
+            } catch (e: Exception) {
+                response.arg2 = ApiServiceException.CODE_INTERNAL_ERROR
+                Log.e(TAG, "Internal error when handle [txnId=$txnId,apiId=$apiId]", e)
+            }
+            try {
+                replyTo.send(response)
+            } catch (e: Exception) {
+                Log.w(TAG, "Fail to send response for [txnId=$txnId,apiId=$apiId]", e)
+                // nothing to do
+            }
+        }
+
+        @VisibleForTesting
+        internal fun findApiHandler(id: Int): ApiHandler<*, *>? {
+            var low = 0
+            var high = apiHandlers.size
+            while (low < high) {
+                val mid = (low + high).ushr(1) // safe from overflows
+                val api = apiHandlers[mid]
+                when {
+                    api.id < id -> low = mid + 1
+                    api.id > id -> high = mid
+                    else -> return api
+                }
+            }
+            return null
+        }
+    }
+
+    companion object {
+        @VisibleForTesting internal const val TAG = "MessengerService"
+    }
+}
+
+@VisibleForTesting
+internal fun List<ApiHandler<*, *>>.toSortedArray() =
+    toTypedArray().also { array ->
+        if (array.isEmpty()) return@also
+        array.sortBy { it.id }
+        if (array[0].id < 0) throw IllegalArgumentException("negative id: ${array[0]}")
+        for (index in 1 until array.size) {
+            if (array[index - 1].id == array[index].id) {
+                throw IllegalArgumentException("conflict id: ${array[index - 1]} ${array[index]}")
+            }
+        }
+    }
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
new file mode 100644
index 0000000..7ffefed
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ipc
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.Bundle
+import android.os.DeadObjectException
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.IBinder
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
+import android.util.Log
+import androidx.annotation.OpenForTesting
+import androidx.annotation.VisibleForTesting
+import androidx.collection.ArrayMap
+import com.google.common.base.Ticker
+import java.util.concurrent.atomic.AtomicInteger
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CompletionHandler
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.DisposableHandle
+
+/**
+ * Client to communicate with [MessengerService].
+ *
+ * A dedicated [HandlerThread] is created to handle requests **sequentially**, there is only one
+ * ongoing request per package.
+ *
+ * Must call [close] before [context] is destroyed to avoid context leaking. Note that
+ * [MessengerService] is automatically unbound when context lifecycle is stopped. Further request
+ * will result in service binding exception.
+ *
+ * @param context context used for service binding, note that context lifecycle affects the IPC
+ *   service lifecycle
+ * @param serviceConnectionIdleMs idle time in milliseconds before closing the service connection
+ * @param name name of the handler thread
+ */
+abstract class MessengerServiceClient
+@JvmOverloads
+constructor(
+    protected val context: Context,
+    private val serviceConnectionIdleMs: Long = 30000L,
+    name: String = TAG,
+    private val metricsLogger: MetricsLogger? = null,
+) : AutoCloseable {
+    /** Per package [ServiceConnection]. */
+    @VisibleForTesting internal val messengers = ArrayMap<String, Connection>()
+    private val handlerThread = HandlerThread(name)
+    @VisibleForTesting internal val handler: Handler
+
+    init {
+        handlerThread.start()
+        val looper = handlerThread.looper
+        handler = Handler(looper)
+    }
+
+    /**
+     * Factory for service [Intent] creation.
+     *
+     * A typical implementation is create [Intent] with specific action.
+     */
+    protected abstract val serviceIntentFactory: () -> Intent
+
+    override fun close() = close(true)
+
+    fun close(join: Boolean) {
+        handler.post {
+            val exception = ClientClosedException()
+            val connections = messengers.values.toTypedArray()
+            for (connection in connections) connection.close(exception)
+        }
+        handlerThread.quitSafely()
+        if (join) handlerThread.join()
+    }
+
+    /**
+     * Invokes given API.
+     *
+     * @param packageName package name of the target service
+     * @param apiDescriptor descriptor of API
+     * @param request request parameter
+     * @return Deferred object of the response, which could be used for [Deferred.await],
+     *   [Deferred.cancel], etc.
+     * @exception ApiException
+     */
+    // TODO: support timeout
+    fun <Request, Response> invoke(
+        packageName: String,
+        apiDescriptor: ApiDescriptor<Request, Response>,
+        request: Request,
+    ): Deferred<Response> {
+        if (apiDescriptor.id < 0) throw ClientInvalidApiException("Invalid id: ${apiDescriptor.id}")
+        if (
+            packageName == context.packageName &&
+                Looper.getMainLooper().thread === Thread.currentThread()
+        ) {
+            // Deadlock as it might involve service creation, which requires main thread
+            throw IllegalStateException("Invoke on main thread causes deadlock")
+        }
+        val wrapper = RequestWrapper(packageName, apiDescriptor, request, txnId.getAndIncrement())
+        metricsLogger?.run {
+            wrapper.logIpcEvent(this, IpcEvent.ENQUEUED)
+            wrapper.deferred.invokeOnCompletion {
+                wrapper.logIpcEvent(this, IpcEvent.COMPLETED, it)
+            }
+        }
+        if (!handler.post { getConnection(packageName).enqueueRequest(wrapper) }) {
+            wrapper.completeExceptionally(ClientClosedException())
+        }
+        return wrapper.deferred
+    }
+
+    private fun getConnection(packageName: String) =
+        messengers.getOrPut(packageName) {
+            Connection(
+                handler.looper,
+                context,
+                packageName,
+                serviceConnectionIdleMs,
+                serviceIntentFactory,
+                messengers,
+                metricsLogger,
+            )
+        }
+
+    @VisibleForTesting
+    internal data class RequestWrapper<Request, Response>(
+        val packageName: String,
+        val apiDescriptor: ApiDescriptor<Request, Response>,
+        val request: Request,
+        val txnId: Int,
+        val deferred: CompletableDeferred<Response> = CompletableDeferred(),
+    ) {
+        val data: Bundle
+            get() = request.let { apiDescriptor.requestCodec.encode(it) }
+
+        fun completeExceptionally(e: Exception) {
+            deferred.completeExceptionally(e)
+        }
+
+        fun logIpcEvent(
+            metricsLogger: MetricsLogger,
+            event: @IpcEvent Int,
+            cause: Throwable? = null,
+        ) {
+            try {
+                metricsLogger.logIpcEvent(
+                    packageName,
+                    txnId,
+                    apiDescriptor.id,
+                    event,
+                    cause,
+                    ticker.read(),
+                )
+            } catch (e: Exception) {
+                Log.e(TAG, "fail to log ipc event: $event", e)
+            }
+        }
+    }
+
+    // NOTE: All ServiceConnection callbacks are invoked from main thread.
+    @OpenForTesting
+    @VisibleForTesting
+    internal open class Connection(
+        looper: Looper,
+        private val context: Context,
+        private val packageName: String,
+        private val serviceConnectionIdleMs: Long,
+        private val serviceIntentFactory: () -> Intent,
+        private val messengers: ArrayMap<String, Connection>,
+        private val metricsLogger: MetricsLogger?,
+    ) : Handler(looper), ServiceConnection {
+        private val clientMessenger = Messenger(this)
+        internal val pendingRequests = ArrayDeque<RequestWrapper<*, *>>()
+        internal var serviceMessenger: Messenger? = null
+        internal open var connectionState: Int = STATE_INIT
+
+        internal var disposableHandle: DisposableHandle? = null
+        private val requestCompletionHandler =
+            object : CompletionHandler {
+                override fun invoke(cause: Throwable?) {
+                    sendEmptyMessage(MSG_CHECK_REQUEST_STATE)
+                }
+            }
+
+        override fun handleMessage(msg: Message) {
+            if (msg.what < 0) {
+                handleClientMessage(msg)
+                return
+            }
+            Log.d(TAG, "receive response $msg")
+            val request = pendingRequests.removeFirstOrNull()
+            if (request == null) {
+                Log.w(TAG, "Pending request is empty when got response")
+                return
+            }
+            if (msg.arg1 != request.txnId || request.apiDescriptor.id != msg.what) {
+                Log.w(TAG, "Mismatch ${request.apiDescriptor.id}, response=$msg")
+                // add request back for retry
+                pendingRequests.addFirst(request)
+                return
+            }
+            handleServiceMessage(request, msg)
+        }
+
+        internal open fun handleClientMessage(msg: Message) {
+            when (msg.what) {
+                MSG_ON_SERVICE_CONNECTED -> {
+                    if (connectionState == STATE_BINDING) {
+                        connectionState = STATE_CONNECTED
+                        serviceMessenger = Messenger(msg.obj as IBinder)
+                        drainPendingRequests()
+                    } else {
+                        Log.w(TAG, "Got onServiceConnected when state is $connectionState")
+                    }
+                }
+                MSG_REBIND_SERVICE -> {
+                    if (pendingRequests.isEmpty()) {
+                        removeMessages(MSG_CLOSE_ON_IDLE)
+                        close(null)
+                    } else {
+                        // died when binding, reset state for rebinding
+                        if (msg.obj != null && connectionState == STATE_BINDING) {
+                            connectionState = STATE_CONNECTED
+                        }
+                        rebindService()
+                    }
+                }
+                MSG_CLOSE_ON_IDLE -> {
+                    if (pendingRequests.isEmpty()) close(null)
+                }
+                MSG_CHECK_REQUEST_STATE -> {
+                    val request = pendingRequests.firstOrNull()
+                    if (request != null && request.deferred.isCompleted) {
+                        drainPendingRequests()
+                    }
+                }
+                else -> Log.e(TAG, "Unknown msg: $msg")
+            }
+        }
+
+        internal open fun handleServiceMessage(request: RequestWrapper<*, *>, response: Message) {
+            @Suppress("UNCHECKED_CAST") val deferred = request.deferred as CompletableDeferred<Any?>
+            if (deferred.isCompleted) {
+                drainPendingRequests()
+                return
+            }
+            metricsLogger?.let { request.logIpcEvent(it, IpcEvent.RESPONSE_RECEIVED) }
+            disposableHandle?.dispose()
+            if (response.arg2 == ApiServiceException.CODE_OK) {
+                try {
+                    deferred.complete(request.apiDescriptor.responseCodec.decode(response.data))
+                } catch (e: Exception) {
+                    request.completeExceptionally(ClientDecodeException(e))
+                }
+            } else {
+                val errorCode = response.arg2
+                val exception = ApiServiceException.of(errorCode)
+                if (exception != null) {
+                    request.completeExceptionally(exception)
+                } else {
+                    request.completeExceptionally(ClientUnknownResponseCodeException(errorCode))
+                }
+            }
+            drainPendingRequests()
+        }
+
+        fun enqueueRequest(request: RequestWrapper<*, *>) {
+            if (connectionState == STATE_CLOSED) {
+                request.completeExceptionally(ClientClosedException())
+                return
+            }
+            pendingRequests.add(request)
+            if (pendingRequests.size == 1) {
+                removeMessages(MSG_CLOSE_ON_IDLE)
+                drainPendingRequests()
+            }
+        }
+
+        override fun onServiceConnected(name: ComponentName, service: IBinder) {
+            Log.i(TAG, "onServiceConnected $name")
+            metricsLogger?.logServiceEvent(ServiceEvent.ON_SERVICE_CONNECTED)
+            sendMessage(obtainMessage(MSG_ON_SERVICE_CONNECTED, service))
+        }
+
+        override fun onServiceDisconnected(name: ComponentName) {
+            // Service process crashed or killed, the connection remains alive, will receive
+            // onServiceConnected when the Service is next running
+            Log.i(TAG, "onServiceDisconnected $name")
+            metricsLogger?.logServiceEvent(ServiceEvent.ON_SERVICE_DISCONNECTED)
+            sendMessage(obtainMessage(MSG_REBIND_SERVICE))
+        }
+
+        override fun onBindingDied(name: ComponentName) {
+            Log.i(TAG, "onBindingDied $name")
+            metricsLogger?.logServiceEvent(ServiceEvent.ON_BINDING_DIED)
+            // When service is connected and peer happens to be updated, both onServiceDisconnected
+            // and onBindingDied callbacks are invoked.
+            if (!hasMessages(MSG_REBIND_SERVICE)) {
+                sendMessage(obtainMessage(MSG_REBIND_SERVICE, true))
+            }
+        }
+
+        internal open fun drainPendingRequests() {
+            disposableHandle = null
+            if (pendingRequests.isEmpty()) {
+                closeOnIdle(serviceConnectionIdleMs)
+                return
+            }
+            val serviceMessenger = this.serviceMessenger
+            if (serviceMessenger == null) {
+                bindService()
+                return
+            }
+            do {
+                val request = pendingRequests.first()
+                if (request.deferred.isCompleted) {
+                    pendingRequests.removeFirst()
+                } else {
+                    sendServiceMessage(serviceMessenger, request)
+                    return
+                }
+            } while (pendingRequests.isNotEmpty())
+            closeOnIdle(serviceConnectionIdleMs)
+        }
+
+        internal open fun closeOnIdle(idleMs: Long) {
+            if (idleMs <= 0 || !sendEmptyMessageDelayed(MSG_CLOSE_ON_IDLE, idleMs)) {
+                close(null)
+            }
+        }
+
+        internal open fun sendServiceMessage(
+            serviceMessenger: Messenger,
+            request: RequestWrapper<*, *>,
+        ) {
+            fun completeExceptionally(exception: Exception) {
+                pendingRequests.removeFirst()
+                request.completeExceptionally(exception)
+                drainPendingRequests()
+            }
+            val message =
+                obtainMessage(request.apiDescriptor.id, request.txnId, 0).apply {
+                    replyTo = clientMessenger
+                }
+            try {
+                message.data = request.data
+            } catch (e: Exception) {
+                completeExceptionally(ClientEncodeException(e))
+                return
+            }
+            Log.d(TAG, "send $message")
+            try {
+                sendServiceMessage(serviceMessenger, message)
+                metricsLogger?.let { request.logIpcEvent(it, IpcEvent.REQUEST_SENT) }
+                disposableHandle = request.deferred.invokeOnCompletion(requestCompletionHandler)
+            } catch (e: DeadObjectException) {
+                Log.w(TAG, "Got DeadObjectException")
+                rebindService()
+            } catch (e: Exception) {
+                completeExceptionally(ClientSendException("Fail to send $message", e))
+            }
+        }
+
+        @Throws(Exception::class)
+        internal open fun sendServiceMessage(serviceMessenger: Messenger, message: Message) =
+            serviceMessenger.send(message)
+
+        internal fun bindService() {
+            if (connectionState == STATE_BINDING || connectionState == STATE_CLOSED) {
+                Log.w(TAG, "Ignore bindService $packageName, state: $connectionState")
+                return
+            }
+            connectionState = STATE_BINDING
+            Log.i(TAG, "bindService $packageName")
+            val intent = serviceIntentFactory.invoke()
+            intent.setPackage(packageName)
+            metricsLogger?.logServiceEvent(ServiceEvent.BIND_SERVICE)
+            bindService(intent)?.let { close(it) }
+        }
+
+        private fun bindService(intent: Intent): Exception? =
+            try {
+                if (context.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+                    null
+                } else {
+                    ClientBindServiceException(null)
+                }
+            } catch (e: Exception) {
+                ClientBindServiceException(e)
+            }
+
+        internal open fun rebindService() {
+            Log.i(TAG, "rebindService $packageName")
+            metricsLogger?.logServiceEvent(ServiceEvent.REBIND_SERVICE)
+            unbindService()
+            bindService()
+        }
+
+        internal fun close(exception: Exception?) {
+            Log.i(TAG, "close connection $packageName", exception)
+            connectionState = STATE_CLOSED
+            messengers.remove(packageName, this)
+            unbindService()
+            if (pendingRequests.isNotEmpty()) {
+                val reason = exception ?: ClientClosedException()
+                do {
+                    pendingRequests.removeFirst().deferred.completeExceptionally(reason)
+                } while (pendingRequests.isNotEmpty())
+            }
+        }
+
+        private fun unbindService() {
+            disposableHandle?.dispose()
+            disposableHandle = null
+            serviceMessenger = null
+            metricsLogger?.logServiceEvent(ServiceEvent.UNBIND_SERVICE)
+            try {
+                // "IllegalArgumentException: Service not registered" may be raised when peer app is
+                // just updated (e.g. upgraded)
+                context.unbindService(this)
+            } catch (e: Exception) {
+                Log.w(TAG, "exception raised when unbindService", e)
+            }
+        }
+
+        private fun MetricsLogger.logServiceEvent(event: @ServiceEvent Int) {
+            try {
+                logServiceEvent(packageName, event, ticker.read())
+            } catch (e: Exception) {
+                Log.e(TAG, "fail to log service event: $event", e)
+            }
+        }
+    }
+
+    companion object {
+        private const val TAG = "MessengerServiceClient"
+        private val ticker: Ticker by lazy { Ticker.systemTicker() }
+
+        @VisibleForTesting internal const val STATE_INIT = 0
+        @VisibleForTesting internal const val STATE_BINDING = 1
+        @VisibleForTesting internal const val STATE_CONNECTED = 2
+        @VisibleForTesting internal const val STATE_CLOSED = 3
+
+        @VisibleForTesting internal const val MSG_ON_SERVICE_CONNECTED = -1
+        @VisibleForTesting internal const val MSG_REBIND_SERVICE = -2
+        @VisibleForTesting internal const val MSG_CLOSE_ON_IDLE = -3
+        @VisibleForTesting internal const val MSG_CHECK_REQUEST_STATE = -4
+
+        @VisibleForTesting internal val txnId = AtomicInteger()
+    }
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MetricsLogger.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MetricsLogger.kt
new file mode 100644
index 0000000..795a920
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MetricsLogger.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.settingslib.ipc
+
+import androidx.annotation.IntDef
+
+/** Interface for metrics logging. */
+interface MetricsLogger {
+
+    /**
+     * Logs service connection event.
+     *
+     * @param packageName package name of the service connection
+     * @param event service event type
+     * @param elapsedRealtimeNanos nanoseconds since boot, including time spent in sleep
+     * @see [android.os.SystemClock.elapsedRealtimeNanos]
+     */
+    fun logServiceEvent(packageName: String, event: @ServiceEvent Int, elapsedRealtimeNanos: Long)
+
+    /**
+     * Logs ipc call event.
+     *
+     * @param packageName package name of the service connection
+     * @param txnId unique transaction id of the ipc call
+     * @param ipc ipc API id
+     * @param event ipc event type
+     * @param cause cause when ipc request completed, provided only when [event] is
+     *   [IpcEvent.COMPLETED]
+     * @param elapsedRealtimeNanos nanoseconds since boot, including time spent in sleep
+     * @see [android.os.SystemClock.elapsedRealtimeNanos]
+     */
+    fun logIpcEvent(
+        packageName: String,
+        txnId: Int,
+        ipc: Int,
+        event: Int,
+        cause: Throwable?,
+        elapsedRealtimeNanos: Long,
+    )
+}
+
+/** Service connection events (for client). */
+@Target(AnnotationTarget.TYPE)
+@IntDef(
+    ServiceEvent.BIND_SERVICE,
+    ServiceEvent.UNBIND_SERVICE,
+    ServiceEvent.REBIND_SERVICE,
+    ServiceEvent.ON_SERVICE_CONNECTED,
+    ServiceEvent.ON_SERVICE_DISCONNECTED,
+    ServiceEvent.ON_BINDING_DIED,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class ServiceEvent {
+    companion object {
+        /** Event of [android.content.Context.bindService] call. */
+        const val BIND_SERVICE = 0
+
+        /** Event of [android.content.Context.unbindService] call. */
+        const val UNBIND_SERVICE = 1
+
+        /** Event to rebind service. */
+        const val REBIND_SERVICE = 2
+
+        /** Event of [android.content.ServiceConnection.onServiceConnected] callback. */
+        const val ON_SERVICE_CONNECTED = 3
+
+        /** Event of [android.content.ServiceConnection.onServiceDisconnected] callback. */
+        const val ON_SERVICE_DISCONNECTED = 4
+
+        /** Event of [android.content.ServiceConnection.onBindingDied] callback. */
+        const val ON_BINDING_DIED = 5
+    }
+}
+
+/** Events of a ipc call. */
+@Target(AnnotationTarget.TYPE)
+@IntDef(IpcEvent.ENQUEUED, IpcEvent.REQUEST_SENT, IpcEvent.RESPONSE_RECEIVED, IpcEvent.COMPLETED)
+@Retention(AnnotationRetention.SOURCE)
+annotation class IpcEvent {
+    companion object {
+        /** Event of IPC request enqueued. */
+        const val ENQUEUED = 0
+
+        /** Event of IPC request has been sent to service. */
+        const val REQUEST_SENT = 1
+
+        /** Event of IPC response received from service. */
+        const val RESPONSE_RECEIVED = 2
+
+        /** Event of IPC request completed. */
+        const val COMPLETED = 3
+    }
+}
diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/PermissionChecker.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/PermissionChecker.kt
new file mode 100644
index 0000000..da9c955
--- /dev/null
+++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/PermissionChecker.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.ipc
+
+import android.app.Application
+import android.content.pm.PackageManager
+import androidx.collection.mutableIntIntMapOf
+
+/** Checker for permission. */
+fun interface PermissionChecker {
+    /**
+     * Checks permission.
+     *
+     * @param application application context
+     * @param myUid uid of current process
+     * @param callingUid uid of peer process
+     */
+    fun check(application: Application, myUid: Int, callingUid: Int): Boolean
+}
+
+/** Verifies apk signatures as permission check. */
+class SignatureChecker : PermissionChecker {
+    private val cache = mutableIntIntMapOf()
+
+    override fun check(application: Application, myUid: Int, callingUid: Int): Boolean =
+        cache.getOrPut(callingUid) {
+            application.packageManager.checkSignatures(myUid, callingUid)
+        } == PackageManager.SIGNATURE_MATCH
+}
diff --git a/packages/SettingsLib/Ipc/testutils/com/android/settingslib/ipc/MessengerServiceRule.kt b/packages/SettingsLib/Ipc/testutils/com/android/settingslib/ipc/MessengerServiceRule.kt
new file mode 100644
index 0000000..8b2deaf
--- /dev/null
+++ b/packages/SettingsLib/Ipc/testutils/com/android/settingslib/ipc/MessengerServiceRule.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ipc
+
+import android.app.Application
+import android.app.Service
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Build
+import android.os.Looper
+import androidx.test.core.app.ApplicationProvider
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import org.robolectric.Robolectric
+import org.robolectric.Shadows
+import org.robolectric.android.controller.ServiceController
+
+/** Rule for messenger service testing. */
+open class MessengerServiceRule<C : MessengerServiceClient>(
+    private val serviceClass: Class<out MessengerService>,
+    val client: C,
+) : TestWatcher() {
+    val application: Application = ApplicationProvider.getApplicationContext()
+    val isRobolectric = Build.FINGERPRINT.contains("robolectric")
+
+    private var serviceController: ServiceController<out Service>? = null
+
+    override fun starting(description: Description) {
+        if (isRobolectric) {
+            runBlocking { setupRobolectricService() }
+        }
+    }
+
+    override fun finished(description: Description) {
+        client.close()
+        if (isRobolectric) {
+            runBlocking {
+                withContext(Dispatchers.Main) { serviceController?.run { unbind().destroy() } }
+            }
+        }
+    }
+
+    private suspend fun setupRobolectricService() {
+        if (Thread.currentThread() == Looper.getMainLooper().thread) {
+            throw IllegalStateException(
+                "To avoid deadlock, run test with @LooperMode(LooperMode.Mode.INSTRUMENTATION_TEST)"
+            )
+        }
+        withContext(Dispatchers.Main) {
+            serviceController = Robolectric.buildService(serviceClass)
+            val service = serviceController!!.create().get()
+            Shadows.shadowOf(application).apply {
+                setComponentNameAndServiceForBindService(
+                    ComponentName(application, serviceClass),
+                    service.onBind(Intent(application, serviceClass)),
+                )
+                setBindServiceCallsOnServiceConnectedDirectly(true)
+                setUnbindServiceCallsOnServiceDisconnected(false)
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index ffd2879..83d657e 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -22,7 +22,7 @@
 import com.android.settingslib.spa.framework.common.SpaEnvironment
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
-import com.android.settingslib.spa.gallery.card.CardPageProvider
+import com.android.settingslib.spa.gallery.banner.BannerPageProvider
 import com.android.settingslib.spa.gallery.chart.ChartPageProvider
 import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
 import com.android.settingslib.spa.gallery.dialog.NavDialogProvider
@@ -107,7 +107,7 @@
                 SettingsTextFieldPasswordPageProvider,
                 SearchScaffoldPageProvider,
                 SuwScaffoldPageProvider,
-                CardPageProvider,
+                BannerPageProvider,
                 CopyablePageProvider,
             ),
             rootPages = listOf(
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/banner/BannerPageProvider.kt
similarity index 77%
rename from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
rename to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/banner/BannerPageProvider.kt
index 5dd7caf..6edd917 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/banner/BannerPageProvider.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.spa.gallery.card
+package com.android.settingslib.spa.gallery.banner
 
 import android.os.Bundle
 import androidx.compose.foundation.clickable
@@ -46,39 +46,39 @@
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.gallery.R
-import com.android.settingslib.spa.widget.card.CardButton
-import com.android.settingslib.spa.widget.card.CardModel
-import com.android.settingslib.spa.widget.card.SettingsCard
-import com.android.settingslib.spa.widget.card.SettingsCardContent
-import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
+import com.android.settingslib.spa.widget.banner.BannerButton
+import com.android.settingslib.spa.widget.banner.BannerModel
+import com.android.settingslib.spa.widget.banner.SettingsBanner
+import com.android.settingslib.spa.widget.banner.SettingsBannerContent
+import com.android.settingslib.spa.widget.banner.SettingsCollapsibleBanner
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 
-object CardPageProvider : SettingsPageProvider {
-    override val name = "Card"
+object BannerPageProvider : SettingsPageProvider {
+    override val name = "Banner"
 
     override fun getTitle(arguments: Bundle?) = TITLE
 
     @Composable
     override fun Page(arguments: Bundle?) {
         RegularScaffold(title = TITLE) {
-            SettingsCardWithIcon()
-            SettingsCardWithoutIcon()
-            SampleSettingsCollapsibleCard()
-            SampleSettingsCardContent()
+            SettingsBannerWithIcon()
+            SettingsBannerWithoutIcon()
+            SampleSettingsCollapsibleBanner()
+            SampleSettingsBannerContent()
         }
     }
 
     @Composable
-    private fun SettingsCardWithIcon() {
-        SettingsCard(
-            CardModel(
+    private fun SettingsBannerWithIcon() {
+        SettingsBanner(
+            BannerModel(
                 title = stringResource(R.string.sample_title),
                 text = stringResource(R.string.sample_text),
                 imageVector = Icons.Outlined.WarningAmber,
                 buttons = listOf(
-                    CardButton(text = "Action") {},
+                    BannerButton(text = "Action") {},
                 ),
                 tintColor = MaterialTheme.colorScheme.error,
                 containerColor = MaterialTheme.colorScheme.errorContainer,
@@ -87,11 +87,11 @@
     }
 
     @Composable
-    private fun SettingsCardWithoutIcon() {
+    private fun SettingsBannerWithoutIcon() {
         val sampleTitle = stringResource(R.string.sample_title)
         var title by remember { mutableStateOf(sampleTitle) }
-        SettingsCard(
-            CardModel(
+        SettingsBanner(
+            BannerModel(
                 title = title,
                 text = stringResource(R.string.sample_text),
             ) { title = "Clicked" }
@@ -99,46 +99,46 @@
     }
 
     @Composable
-    fun SampleSettingsCollapsibleCard() {
+    fun SampleSettingsCollapsibleBanner() {
         val context = LocalContext.current
         var isVisible0 by rememberSaveable { mutableStateOf(true) }
         var isVisible1 by rememberSaveable { mutableStateOf(true) }
-        val cards = remember {
+        val banners = remember {
             mutableStateListOf(
-                CardModel(
+                BannerModel(
                     title = context.getString(R.string.sample_title),
                     text = context.getString(R.string.sample_text),
                     imageVector = Icons.Outlined.PowerOff,
                     isVisible = { isVisible0 },
                     onDismiss = { isVisible0 = false },
                     buttons = listOf(
-                        CardButton(text = "Override") {},
-                        CardButton(text = "Learn more") {},
+                        BannerButton(text = "Override") {},
+                        BannerButton(text = "Learn more") {},
                     ),
                 ),
-                CardModel(
+                BannerModel(
                     title = context.getString(R.string.sample_title),
                     text = context.getString(R.string.sample_text),
                     imageVector = Icons.Outlined.Shield,
                     isVisible = { isVisible1 },
                     onDismiss = { isVisible1 = false },
                     buttons = listOf(
-                        CardButton(text = "Action") {},
+                        BannerButton(text = "Action") {},
                     ),
                 )
             )
         }
-        SettingsCollapsibleCard(
+        SettingsCollapsibleBanner(
             title = "More alerts",
             imageVector = Icons.Outlined.Error,
-            models = cards.toList()
+            models = banners.toList()
         )
     }
 
     @Composable
-    fun SampleSettingsCardContent() {
-        SettingsCard {
-            SettingsCardContent {
+    fun SampleSettingsBannerContent() {
+        SettingsBanner {
+            SettingsBannerContent {
                 Box(
                     Modifier
                         .fillMaxWidth()
@@ -148,7 +148,7 @@
                     Text(text = "Abc")
                 }
             }
-            SettingsCardContent {
+            SettingsBannerContent {
                 Box(
                     Modifier
                         .fillMaxWidth()
@@ -171,13 +171,13 @@
             }
     }
 
-    private const val TITLE = "Sample Card"
+    private const val TITLE = "Sample Banner"
 }
 
 @Preview
 @Composable
-private fun CardPagePreview() {
+private fun BannerPagePreview() {
     SettingsTheme {
-        CardPageProvider.Page(null)
+        BannerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
index 654719d..b1558cc 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
@@ -28,7 +28,7 @@
 import com.android.settingslib.spa.gallery.R
 import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
 import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
-import com.android.settingslib.spa.gallery.card.CardPageProvider
+import com.android.settingslib.spa.gallery.banner.BannerPageProvider
 import com.android.settingslib.spa.gallery.chart.ChartPageProvider
 import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider
 import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
@@ -73,7 +73,7 @@
             ChartPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             DialogMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             EditorMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
-            CardPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            BannerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             CopyablePageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
         )
     }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/BannerModel.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/BannerModel.kt
new file mode 100644
index 0000000..4ef258f
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/BannerModel.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.banner
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+
+data class BannerButton(
+    val text: String,
+    val contentDescription: String? = null,
+    val onClick: () -> Unit,
+)
+
+data class BannerModel(
+    val title: String,
+    val text: String,
+    val imageVector: ImageVector? = null,
+    val isVisible: () -> Boolean = { true },
+
+    /**
+     * A dismiss button will be displayed if this is not null.
+     *
+     * And this callback will be called when user clicks the button.
+     */
+    val onDismiss: (() -> Unit)? = null,
+
+    val buttons: List<BannerButton> = emptyList(),
+
+    /** If specified, this color will be used to tint the icon and the buttons. */
+    val tintColor: Color = Color.Unspecified,
+
+    /** If specified, this color will be used to tint the icon and the buttons. */
+    val containerColor: Color = Color.Unspecified,
+
+    val onClick: (() -> Unit)? = null,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
new file mode 100644
index 0000000..e3f4860
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsBanner.kt
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.banner
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
+import androidx.compose.material.icons.outlined.WarningAmber
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.debug.UiModePreviews
+import com.android.settingslib.spa.framework.compose.contentDescription
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraLarge
+import com.android.settingslib.spa.framework.theme.SettingsShape.CornerExtraSmall
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.ui.SettingsBody
+import com.android.settingslib.spa.widget.ui.SettingsTitle
+
+@Composable
+fun SettingsBanner(content: @Composable ColumnScope.() -> Unit) {
+    Card(
+        shape = CornerExtraLarge,
+        colors = CardDefaults.cardColors(
+            containerColor = Color.Transparent,
+        ),
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(
+                horizontal = SettingsDimension.itemPaddingEnd,
+                vertical = SettingsDimension.itemPaddingAround,
+            ),
+        content = content,
+    )
+}
+
+@Composable
+fun SettingsBannerContent(
+    containerColor: Color = Color.Unspecified,
+    content: @Composable ColumnScope.() -> Unit,
+) {
+    Card(
+        shape = CornerExtraSmall,
+        colors = CardDefaults.cardColors(
+            containerColor = containerColor.takeOrElse { MaterialTheme.colorScheme.surface },
+        ),
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(vertical = 1.dp),
+        content = content,
+    )
+}
+
+@Composable
+fun SettingsBanner(model: BannerModel) {
+    SettingsBanner {
+        SettingsBannerImpl(model)
+    }
+}
+
+@Composable
+internal fun SettingsBannerImpl(model: BannerModel) {
+    AnimatedVisibility(visible = model.isVisible()) {
+        SettingsBannerContent(containerColor = model.containerColor) {
+            Column(
+                modifier = (model.onClick?.let { Modifier.clickable(onClick = it) } ?: Modifier)
+                    .padding(
+                        horizontal = SettingsDimension.dialogItemPaddingHorizontal,
+                        vertical = SettingsDimension.itemPaddingAround,
+                    ),
+                verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
+            ) {
+                BannerHeader(model.imageVector, model.tintColor, model.onDismiss)
+                SettingsTitle(model.title)
+                SettingsBody(model.text)
+                Buttons(model.buttons, model.tintColor)
+            }
+        }
+    }
+}
+
+@Composable
+fun BannerHeader(imageVector: ImageVector?, iconColor: Color, onDismiss: (() -> Unit)? = null) {
+    if (imageVector != null || onDismiss != null) {
+        Spacer(Modifier.height(SettingsDimension.buttonPaddingVertical))
+    }
+    Row(Modifier.fillMaxWidth()) {
+        BannerIcon(imageVector, iconColor)
+        Spacer(modifier = Modifier.weight(1f))
+        DismissButton(onDismiss)
+    }
+}
+
+@Composable
+private fun BannerIcon(imageVector: ImageVector?, color: Color) {
+    if (imageVector != null) {
+        Icon(
+            imageVector = imageVector,
+            contentDescription = null,
+            modifier = Modifier.size(SettingsDimension.itemIconSize),
+            tint = color.takeOrElse { MaterialTheme.colorScheme.primary },
+        )
+    }
+}
+
+@Composable
+private fun DismissButton(onDismiss: (() -> Unit)?) {
+    if (onDismiss == null) return
+    Surface(
+        shape = CircleShape,
+        color = MaterialTheme.colorScheme.secondaryContainer,
+    ) {
+        IconButton(
+            onClick = onDismiss,
+            modifier = Modifier.size(SettingsDimension.itemIconSize)
+        ) {
+            Icon(
+                imageVector = Icons.Outlined.Close,
+                contentDescription = stringResource(
+                    androidx.compose.material3.R.string.m3c_snackbar_dismiss
+                ),
+                modifier = Modifier.padding(SettingsDimension.paddingSmall),
+            )
+        }
+    }
+}
+
+@OptIn(ExperimentalLayoutApi::class)
+@Composable
+private fun Buttons(buttons: List<BannerButton>, color: Color) {
+    if (buttons.isNotEmpty()) {
+        FlowRow(
+            modifier = Modifier.fillMaxWidth(),
+            horizontalArrangement = Arrangement.spacedBy(
+                space = SettingsDimension.itemPaddingEnd,
+                alignment = Alignment.End,
+            ),
+        ) {
+            for (button in buttons) {
+                Button(button, color)
+            }
+        }
+    } else {
+        Spacer(Modifier.height(SettingsDimension.itemPaddingAround))
+    }
+}
+
+@Composable
+private fun Button(button: BannerButton, color: Color) {
+    TextButton(
+        onClick = button.onClick,
+        modifier = Modifier.contentDescription(button.contentDescription),
+    ) {
+        Text(text = button.text, color = color)
+    }
+}
+
+@UiModePreviews
+@Composable
+private fun SettingsBannerPreview() {
+    SettingsTheme {
+        SettingsBanner(
+            BannerModel(
+                title = "Lorem ipsum",
+                text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+                imageVector = Icons.Outlined.WarningAmber,
+                buttons = listOf(
+                    BannerButton(text = "Action") {},
+                )
+            )
+        )
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsCollapsibleBanner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsCollapsibleBanner.kt
new file mode 100644
index 0000000..31a1e9c
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/banner/SettingsCollapsibleBanner.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.banner
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Error
+import androidx.compose.material.icons.outlined.PowerOff
+import androidx.compose.material.icons.outlined.Shield
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import com.android.settingslib.spa.debug.UiModePreviews
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.ui.ExpandIcon
+import com.android.settingslib.spa.widget.ui.SettingsDialogItem
+import com.android.settingslib.spa.widget.ui.SettingsTitleSmall
+
+@Composable
+fun SettingsCollapsibleBanner(
+    title: String,
+    imageVector: ImageVector,
+    models: List<BannerModel>,
+) {
+    var expanded by rememberSaveable { mutableStateOf(false) }
+    SettingsBanner {
+        SettingsBannerContent {
+            Header(title, imageVector, models.count { it.isVisible() }, expanded) { expanded = it }
+        }
+        AnimatedVisibility(expanded) {
+            Column {
+                for (model in models) {
+                    SettingsBannerImpl(model)
+                }
+            }
+        }
+    }
+}
+
+@Composable
+private fun Header(
+    title: String,
+    imageVector: ImageVector,
+    cardCount: Int,
+    expanded: Boolean,
+    setExpanded: (Boolean) -> Unit,
+) {
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .clickable { setExpanded(!expanded) }
+            .padding(
+                horizontal = SettingsDimension.itemPaddingStart,
+                vertical = SettingsDimension.itemPaddingVertical,
+            ),
+        horizontalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingStart),
+        verticalAlignment = Alignment.CenterVertically,
+    ) {
+        Icon(
+            imageVector = imageVector,
+            contentDescription = null,
+            modifier = Modifier.size(SettingsDimension.itemIconSize),
+            tint = MaterialTheme.colorScheme.primary,
+        )
+        Box(modifier = Modifier.weight(1f)) {
+            SettingsTitleSmall(title, useMediumWeight = true)
+        }
+        BannerCount(cardCount, expanded)
+    }
+}
+
+@Composable
+private fun BannerCount(modelSize: Int, expanded: Boolean) {
+    Surface(
+        shape = SettingsShape.CornerExtraLarge,
+        color = MaterialTheme.colorScheme.secondaryContainer,
+    ) {
+        Row(
+            modifier = Modifier.padding(SettingsDimension.paddingSmall),
+            verticalAlignment = Alignment.CenterVertically,
+        ) {
+            Spacer(modifier = Modifier.padding(SettingsDimension.paddingSmall))
+            SettingsDialogItem(modelSize.toString())
+            ExpandIcon(expanded)
+        }
+    }
+}
+
+@UiModePreviews
+@Composable
+private fun SettingsCollapsibleBannerPreview() {
+    SettingsTheme {
+        SettingsCollapsibleBanner(
+            title = "More alerts",
+            imageVector = Icons.Outlined.Error,
+            models = listOf(
+                BannerModel(
+                    title = "Lorem ipsum",
+                    text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+                    imageVector = Icons.Outlined.PowerOff,
+                    buttons = listOf(
+                        BannerButton(text = "Action") {},
+                    )
+                ),
+                BannerModel(
+                    title = "Lorem ipsum",
+                    text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+                    imageVector = Icons.Outlined.Shield,
+                    buttons = listOf(
+                        BannerButton(text = "Action") {},
+                    )
+                )
+            )
+        )
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsBannerTest.kt
similarity index 79%
rename from packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
rename to packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsBannerTest.kt
index ffc7e86..a8479b0 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsBannerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.spa.widget.card
+package com.android.settingslib.spa.widget.banner
 
 import android.content.Context
 import androidx.compose.runtime.getValue
@@ -35,16 +35,16 @@
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
-class SettingsCardTest {
+class SettingsBannerTest {
     @get:Rule val composeTestRule = createComposeRule()
 
     private val context: Context = ApplicationProvider.getApplicationContext()
 
     @Test
-    fun settingsCard_titleDisplayed() {
+    fun settingsBanner_titleDisplayed() {
         composeTestRule.setContent {
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = TITLE,
                     text = "",
                 )
@@ -55,10 +55,10 @@
     }
 
     @Test
-    fun settingsCard_textDisplayed() {
+    fun settingsBanner_textDisplayed() {
         composeTestRule.setContent {
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = "",
                     text = TEXT,
                 )
@@ -69,13 +69,13 @@
     }
 
     @Test
-    fun settingsCard_buttonDisplayed() {
+    fun settingsBanner_buttonDisplayed() {
         composeTestRule.setContent {
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = "",
                     text = "",
-                    buttons = listOf(CardButton(text = TEXT) {}),
+                    buttons = listOf(BannerButton(text = TEXT) {}),
                 )
             )
         }
@@ -84,14 +84,14 @@
     }
 
     @Test
-    fun settingsCard_buttonCanBeClicked() {
+    fun settingsBanner_buttonCanBeClicked() {
         var buttonClicked = false
         composeTestRule.setContent {
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = "",
                     text = "",
-                    buttons = listOf(CardButton(text = TEXT) { buttonClicked = true }),
+                    buttons = listOf(BannerButton(text = TEXT) { buttonClicked = true }),
                 )
             )
         }
@@ -102,13 +102,13 @@
     }
 
     @Test
-    fun settingsCard_buttonHaveContentDescription() {
+    fun settingsBanner_buttonHaveContentDescription() {
         composeTestRule.setContent {
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = "",
                     text = "",
-                    buttons = listOf(CardButton(
+                    buttons = listOf(BannerButton(
                         text = TEXT,
                         contentDescription = CONTENT_DESCRIPTION,
                         ) {}
@@ -121,11 +121,11 @@
     }
 
     @Test
-    fun settingsCard_dismiss() {
+    fun settingsBanner_dismiss() {
         composeTestRule.setContent {
             var isVisible by remember { mutableStateOf(true) }
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = TITLE,
                     text = "",
                     isVisible = { isVisible },
@@ -142,11 +142,11 @@
     }
 
     @Test
-    fun settingsCard_clickable() {
+    fun settingsBanner_clickable() {
         var clicked by mutableStateOf(false)
         composeTestRule.setContent {
-            SettingsCard(
-                CardModel(
+            SettingsBanner(
+                BannerModel(
                     title = TITLE,
                     text = "",
                 ) { clicked = true }
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleBannerTest.kt
similarity index 78%
rename from packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
rename to packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleBannerTest.kt
index aba9d7b..1080fde 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleBannerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.spa.widget.card
+package com.android.settingslib.spa.widget.banner
 
 import android.content.Context
 import androidx.compose.material.icons.Icons
@@ -36,44 +36,44 @@
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
-class SettingsCollapsibleCardTest {
+class SettingsCollapsibleBannerTest {
     @get:Rule
     val composeTestRule = createComposeRule()
 
     private val context: Context = ApplicationProvider.getApplicationContext()
 
     @Test
-    fun settingsCollapsibleCard_titleDisplayed() {
+    fun settingsCollapsibleBanner_titleDisplayed() {
         setContent()
 
         composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
     }
 
     @Test
-    fun settingsCollapsibleCard_cardCountDisplayed() {
+    fun settingsCollapsibleBanner_BannerCountDisplayed() {
         setContent()
 
         composeTestRule.onNodeWithText("1").assertIsDisplayed()
     }
 
     @Test
-    fun settingsCollapsibleCard_initial_cardTextNotExists() {
+    fun settingsCollapsibleBanner_initial_BannerTextNotExists() {
         setContent()
 
-        composeTestRule.onNodeWithText(CARD_TEXT).assertDoesNotExist()
+        composeTestRule.onNodeWithText(Banner_TEXT).assertDoesNotExist()
     }
 
     @Test
-    fun settingsCollapsibleCard_afterExpand_cardTextDisplayed() {
+    fun settingsCollapsibleBanner_afterExpand_BannerTextDisplayed() {
         setContent()
 
         composeTestRule.onNodeWithText(TITLE).performClick()
 
-        composeTestRule.onNodeWithText(CARD_TEXT).assertIsDisplayed()
+        composeTestRule.onNodeWithText(Banner_TEXT).assertIsDisplayed()
     }
 
     @Test
-    fun settingsCollapsibleCard_dismiss() {
+    fun settingsCollapsibleBanner_dismiss() {
         setContent()
         composeTestRule.onNodeWithText(TITLE).performClick()
 
@@ -81,20 +81,20 @@
             context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
         ).performClick()
 
-        composeTestRule.onNodeWithText(CARD_TEXT).isNotDisplayed()
+        composeTestRule.onNodeWithText(Banner_TEXT).isNotDisplayed()
         composeTestRule.onNodeWithText("0").assertIsDisplayed()
     }
 
     private fun setContent() {
         composeTestRule.setContent {
             var isVisible by rememberSaveable { mutableStateOf(true) }
-            SettingsCollapsibleCard(
+            SettingsCollapsibleBanner(
                 title = TITLE,
                 imageVector = Icons.Outlined.Error,
                 models = listOf(
-                    CardModel(
+                    BannerModel(
                         title = "",
-                        text = CARD_TEXT,
+                        text = Banner_TEXT,
                         isVisible = { isVisible },
                         onDismiss = { isVisible = false },
                     )
@@ -105,6 +105,6 @@
 
     private companion object {
         const val TITLE = "Title"
-        const val CARD_TEXT = "Card Text"
+        const val Banner_TEXT = "Banner Text"
     }
 }
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 34b597b..79c3ff9 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -139,3 +139,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "audio_sharing_qs_dialog_improvement"
+    namespace: "cross_device_experiences"
+    description: "Gates whether to enable audio sharing qs dialog improvement"
+    bug: "360759048"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 1e58335..9d56c77 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -520,8 +520,6 @@
 
         if (android.webkit.Flags.updateServiceIpcWrapper()) {
             if (pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
-                // WebViewUpdateManager.getInstance() will not return null on devices with
-                // FEATURE_WEBVIEW.
                 provider = WebViewUpdateManager.getInstance().getDefaultWebViewPackage();
             }
         } else {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index c6eb9fd..6dab224 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.os.Build;
@@ -356,6 +357,8 @@
         final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
         preferredMainDevice = deviceManager.findDevice(bluetoothDeviceOfPreferredMainDevice);
         if (haveMultiMainDevicesInAllOfDevicesList) {
+            log("addMemberDevicesIntoMainDevice: haveMultiMainDevicesInAllOfDevicesList. "
+                    + "Combine them and also keep the preferred main device as main device.");
             // put another devices into main device.
             for (CachedBluetoothDevice deviceItem : topLevelOfGroupDevicesList) {
                 if (deviceItem.getDevice() == null || deviceItem.getDevice().equals(
@@ -376,6 +379,7 @@
                 preferredMainDevice.refresh();
                 hasChanged = true;
             }
+            syncAudioSharingSourceIfNeeded(preferredMainDevice);
         }
         if (hasChanged) {
             log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
@@ -384,6 +388,41 @@
         return hasChanged;
     }
 
+    private void syncAudioSharingSourceIfNeeded(CachedBluetoothDevice mainDevice) {
+        boolean isAudioSharingEnabled = BluetoothUtils.isAudioSharingEnabled();
+        if (isAudioSharingEnabled) {
+            boolean hasBroadcastSource = BluetoothUtils.isBroadcasting(mBtManager)
+                    && BluetoothUtils.hasConnectedBroadcastSource(
+                    mainDevice, mBtManager);
+            if (hasBroadcastSource) {
+                LocalBluetoothLeBroadcast broadcast = mBtManager == null ? null
+                        : mBtManager.getProfileManager().getLeAudioBroadcastProfile();
+                BluetoothLeBroadcastMetadata metadata = broadcast == null ? null :
+                        broadcast.getLatestBluetoothLeBroadcastMetadata();
+                LocalBluetoothLeBroadcastAssistant assistant = mBtManager == null ? null
+                        : mBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+                if (metadata != null && assistant != null) {
+                    log("addMemberDevicesIntoMainDevice: sync audio sharing source after "
+                            + "combining the top level devices.");
+                    Set<CachedBluetoothDevice> deviceSet = new HashSet<>();
+                    deviceSet.add(mainDevice);
+                    deviceSet.addAll(mainDevice.getMemberDevice());
+                    Set<BluetoothDevice> sinksToSync = deviceSet.stream()
+                            .map(CachedBluetoothDevice::getDevice)
+                            .filter(device ->
+                                    !BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(
+                                            device, mBtManager))
+                            .collect(Collectors.toSet());
+                    for (BluetoothDevice device : sinksToSync) {
+                        log("addMemberDevicesIntoMainDevice: sync audio sharing source to "
+                                + device.getAnonymizedAddress());
+                        assistant.addSource(device, metadata, /* isGroupOp= */ false);
+                    }
+                }
+            }
+        }
+    }
+
     private void log(String msg) {
         if (DEBUG) {
             Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
index a0fe5d2..38183d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItem.kt
@@ -36,6 +36,7 @@
     val className: String,
     val intentAction: String,
     val preferenceKey: String? = null,
+    val highlighted: Boolean = false,
     val extras: Bundle = Bundle.EMPTY,
 ) : Parcelable {
 
@@ -47,6 +48,7 @@
             writeString(packageName)
             writeString(className)
             writeString(intentAction)
+            writeBoolean(highlighted)
             writeString(preferenceKey)
             writeBundle(extras)
         }
@@ -63,6 +65,7 @@
                             packageName = readString() ?: "",
                             className = readString() ?: "",
                             intentAction = readString() ?: "",
+                            highlighted = readBoolean(),
                             preferenceKey = readString() ?: "",
                             extras = readBundle((Bundle::class.java.classLoader)) ?: Bundle.EMPTY,
                         )
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
index 4b67ef7..c8c7562 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingPreference.java
@@ -42,6 +42,8 @@
                 return MultiTogglePreference.readFromParcel(in);
             case DeviceSettingType.DEVICE_SETTING_TYPE_FOOTER:
                 return DeviceSettingFooterPreference.readFromParcel(in);
+            case DeviceSettingType.DEVICE_SETTING_TYPE_HELP:
+                return DeviceSettingHelpPreference.readFromParcel(in);
             default:
                 return UNKNOWN;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
index 769b6e6..29664f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/data/repository/DeviceSettingRepository.kt
@@ -110,15 +110,16 @@
             if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
                 BluetoothProfilesItem(
                     settingId,
+                    highlighted,
                     preferenceKey!!,
                     extras.getStringArrayList(DeviceSettingContract.INVISIBLE_PROFILES)
                         ?: emptyList()
                 )
             } else {
-                CommonBuiltinItem(settingId, preferenceKey!!)
+                CommonBuiltinItem(settingId, highlighted, preferenceKey!!)
             }
         } else {
-            AppProvidedItem(settingId)
+            AppProvidedItem(settingId, highlighted)
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
index 08fb3fb..5958c30 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/devicesettings/shared/model/DeviceSettingConfigModel.kt
@@ -34,6 +34,7 @@
 /** Models a device setting item in config. */
 sealed interface DeviceSettingConfigItemModel {
     @DeviceSettingId val settingId: Int
+    val highlighted: Boolean
 
     /** A built-in item in Settings. */
     sealed interface BuiltinItem : DeviceSettingConfigItemModel {
@@ -43,18 +44,22 @@
         /** A general built-in item in Settings. */
         data class CommonBuiltinItem(
             @DeviceSettingId override val settingId: Int,
+            override val highlighted: Boolean,
             override val preferenceKey: String,
         ) : BuiltinItem
 
         /** A bluetooth profiles in Settings. */
         data class BluetoothProfilesItem(
             @DeviceSettingId override val settingId: Int,
+            override val highlighted: Boolean,
             override val preferenceKey: String,
             val invisibleProfiles: List<String>,
         ) : BuiltinItem
     }
 
     /** A remote item provided by other apps. */
-    data class AppProvidedItem(@DeviceSettingId override val settingId: Int) :
-        DeviceSettingConfigItemModel
+    data class AppProvidedItem(
+        @DeviceSettingId override val settingId: Int,
+        override val highlighted: Boolean,
+    ) : DeviceSettingConfigItemModel
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
index 7467ee1..d58add4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/media/OWNERS
@@ -2,7 +2,6 @@
 ethibodeau@google.com
 michaelmikhil@google.com
 apotapov@google.com
-shaoweishen@google.com
 
 #Android Media - For minor changes and renames only.
 aquilescanta@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
index 698eb81..b180b69 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
@@ -18,31 +18,51 @@
 
 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.anyInt;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
+import android.os.Looper;
 import android.os.Parcel;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.settingslib.flags.Flags;
+import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
+
+import com.google.common.collect.ImmutableList;
 
 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;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class CsipDeviceManagerTest {
     private final static String DEVICE_NAME_1 = "TestName_1";
     private final static String DEVICE_NAME_2 = "TestName_2";
@@ -59,6 +79,9 @@
     private final BluetoothClass DEVICE_CLASS_2 =
             createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
     @Mock
@@ -77,7 +100,12 @@
     private A2dpProfile mA2dpProfile;
     @Mock
     private LeAudioProfile mLeAudioProfile;
+    @Mock
+    private LocalBluetoothLeBroadcast mBroadcast;
+    @Mock
+    private LocalBluetoothLeBroadcastAssistant mAssistant;
 
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
     private CachedBluetoothDevice mCachedDevice1;
     private CachedBluetoothDevice mCachedDevice2;
     private CachedBluetoothDevice mCachedDevice3;
@@ -101,6 +129,12 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = RuntimeEnvironment.application;
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mShadowBluetoothAdapter.setEnabled(true);
+        mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+                BluetoothStatusCodes.FEATURE_SUPPORTED);
+        mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
+                BluetoothStatusCodes.FEATURE_SUPPORTED);
         when(mDevice1.getAddress()).thenReturn(DEVICE_ADDRESS_1);
         when(mDevice2.getAddress()).thenReturn(DEVICE_ADDRESS_2);
         when(mDevice3.getAddress()).thenReturn(DEVICE_ADDRESS_3);
@@ -124,6 +158,8 @@
         when(mLocalProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
         when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
         when(mLocalProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
+        when(mLocalProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
+        when(mLocalProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
 
         when(mLeAudioProfile.getConnectedGroupLeadDevice(anyInt())).thenReturn(null);
         mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager);
@@ -307,6 +343,7 @@
         mCachedDevices.add(preferredDevice);
         mCachedDevices.add(mCachedDevice2);
         mCachedDevices.add(mCachedDevice3);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
 
         assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
                 .isTrue();
@@ -314,6 +351,36 @@
         assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
         assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
         assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
+        verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+                any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+    }
+
+    @Test
+    public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncSource() {
+        // Condition: The preferredDevice is main and there is another main device in top list
+        // Expected Result: return true and there is the preferredDevice in top list
+        CachedBluetoothDevice preferredDevice = mCachedDevice1;
+        mCachedDevice1.getMemberDevice().clear();
+        mCachedDevices.clear();
+        mCachedDevices.add(preferredDevice);
+        mCachedDevices.add(mCachedDevice2);
+        mCachedDevices.add(mCachedDevice3);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+        BluetoothLeBroadcastReceiveState state = Mockito.mock(
+                BluetoothLeBroadcastReceiveState.class);
+        when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+        when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
+
+        assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
+                .isTrue();
+        assertThat(mCachedDevices.contains(preferredDevice)).isTrue();
+        assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
+        assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
+        assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
+        verify(mAssistant).addSource(mDevice1, metadata, /* isGroupOp= */ false);
     }
 
     @Test
@@ -341,6 +408,8 @@
         CachedBluetoothDevice preferredDevice = mCachedDevice2;
         BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
         mCachedDevice3.setGroupId(GROUP1);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        when(mBroadcast.isEnabled(null)).thenReturn(false);
 
         assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
                 .isTrue();
@@ -351,8 +420,40 @@
         assertThat(mCachedDevices.contains(mCachedDevice3)).isFalse();
         assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice2);
         assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice3);
+        assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
+        verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+                any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+    }
+
+    @Test
+    public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncSource() {
+        // Condition: The preferredDevice is member and there are two main device in top list
+        // Expected Result: return true and there is the preferredDevice in top list
+        CachedBluetoothDevice preferredDevice = mCachedDevice2;
+        BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
+        mCachedDevice3.setGroupId(GROUP1);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
+        when(mBroadcast.isEnabled(null)).thenReturn(true);
+        BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
+        when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+        BluetoothLeBroadcastReceiveState state = Mockito.mock(
+                BluetoothLeBroadcastReceiveState.class);
+        when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+        when(mAssistant.getAllSources(mDevice1)).thenReturn(ImmutableList.of(state));
+
+        assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
+                .isTrue();
+        shadowOf(Looper.getMainLooper()).idle();
+        // expected main is mCachedDevice1 which is the main of preferredDevice, since system
+        // switch the relationship between preferredDevice and the main of preferredDevice
+        assertThat(mCachedDevices.contains(mCachedDevice1)).isTrue();
+        assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
+        assertThat(mCachedDevices.contains(mCachedDevice3)).isFalse();
+        assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice2);
         assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice3);
         assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
+        verify(mAssistant).addSource(mDevice2, metadata, /* isGroupOp= */ false);
+        verify(mAssistant).addSource(mDevice3, metadata, /* isGroupOp= */ false);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
index 56e9b6c..86071bb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingItemTest.kt
@@ -34,6 +34,8 @@
                 packageName = "package_name",
                 className = "class_name",
                 intentAction = "intent_action",
+                preferenceKey = "key1",
+                highlighted = true,
                 extras = Bundle().apply { putString("key1", "value1") },
             )
 
@@ -43,6 +45,7 @@
         assertThat(fromParcel.packageName).isEqualTo(item.packageName)
         assertThat(fromParcel.className).isEqualTo(item.className)
         assertThat(fromParcel.intentAction).isEqualTo(item.intentAction)
+        assertThat(fromParcel.preferenceKey).isEqualTo(item.preferenceKey)
         assertThat(fromParcel.extras.getString("key1")).isEqualTo(item.extras.getString("key1"))
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
index a0a2658..7f17293 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/devicesettings/DeviceSettingsConfigTest.kt
@@ -33,30 +33,33 @@
                 mainContentItems =
                     listOf(
                         DeviceSettingItem(
-                            1,
-                            "package_name_1",
-                            "class_name_1",
-                            "intent_action_1",
-                            null,
-                            Bundle(),
+                            settingId = 1,
+                            packageName = "package_name_1",
+                            className = "class_name_1",
+                            intentAction = "intent_action_1",
+                            preferenceKey = null,
+                            highlighted = false,
+                            extras = Bundle(),
                         )),
                 moreSettingsItems =
                     listOf(
                         DeviceSettingItem(
-                            2,
-                            "package_name_2",
-                            "class_name_2",
-                            "intent_action_2",
-                            null,
-                            Bundle(),
+                            settingId = 2,
+                            packageName = "package_name_2",
+                            className = "class_name_2",
+                            intentAction = "intent_action_2",
+                            preferenceKey = null,
+                            highlighted = false,
+                            extras = Bundle(),
                         )),
                 moreSettingsHelpItem = DeviceSettingItem(
-                    3,
-                    "package_name_2",
-                    "class_name_2",
-                    "intent_action_2",
-                    null,
-                    Bundle(),
+                    settingId = 3,
+                    packageName = "package_name_2",
+                    className = "class_name_2",
+                    intentAction = "intent_action_2",
+                    preferenceKey = null,
+                    highlighted = false,
+                    extras = Bundle(),
                 ),
                 extras = Bundle().apply { putString("key1", "value1") },
             )
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 62401a1..aca26ec 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
@@ -91,3 +91,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "support_local_overrides_sysprops"
+    namespace: "core_experiments_team_internal"
+    description: "When DeviceConfig overrides are deleted, delete new storage overrides too."
+    bug: "366022906"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index d39b564..b491b5a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -223,6 +223,7 @@
                     Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
                     Settings.Global.ENABLE_DISKSTATS_LOGGING,
                     Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+                    Settings.Global.ENABLE_USE_APP_INFO_NOT_LAUNCHED,
                     Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
                     Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                     Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
diff --git a/packages/Shell/tests/Android.bp b/packages/Shell/tests/Android.bp
index 6399ffd..082a589 100644
--- a/packages/Shell/tests/Android.bp
+++ b/packages/Shell/tests/Android.bp
@@ -26,3 +26,10 @@
     instrumentation_for: "Shell",
     certificate: "platform",
 }
+
+test_module_config {
+    name: "ShellTests_android_server_os",
+    base: "ShellTests",
+    test_suites: ["device-tests"],
+    exclude_annotations: ["androidx.test.filters.LargeTest"],
+}
diff --git a/packages/SystemUI/animation/lib/Android.bp b/packages/SystemUI/animation/lib/Android.bp
new file mode 100644
index 0000000..4324d463
--- /dev/null
+++ b/packages/SystemUI/animation/lib/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    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"],
+}
+
+java_library {
+    name: "PlatformAnimationLib-server",
+    srcs: [
+        "src/com/android/systemui/animation/server/*.java",
+        ":PlatformAnimationLib-aidl",
+    ],
+    static_libs: [
+        "WindowManager-Shell-shared",
+    ],
+}
+
+filegroup {
+    name: "PlatformAnimationLib-aidl",
+    srcs: [
+        "src/**/*.aidl",
+    ],
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
new file mode 100644
index 0000000..3cbb688
--- /dev/null
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation.server;
+
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.SurfaceControl;
+import android.window.IRemoteTransition;
+import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
+import android.window.TransitionFilter;
+import android.window.TransitionInfo;
+import android.window.TransitionInfo.Change;
+import android.window.WindowAnimationState;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.systemui.animation.shared.IOriginTransitions;
+import com.android.wm.shell.shared.ShellTransitions;
+import com.android.wm.shell.shared.TransitionUtil;
+
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Predicate;
+
+/** An implementation of the {@link IOriginTransitions}. */
+public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
+    private static final boolean DEBUG = true;
+    private static final String TAG = "OriginTransitions";
+
+    private final Object mLock = new Object();
+    private final ShellTransitions mShellTransitions;
+    private final Context mContext;
+
+    @GuardedBy("mLock")
+    private final Map<IBinder, OriginTransitionRecord> mRecords = new ArrayMap<>();
+
+    public IOriginTransitionsImpl(Context context, ShellTransitions shellTransitions) {
+        mShellTransitions = shellTransitions;
+        mContext = context;
+    }
+
+    @Override
+    public RemoteTransition makeOriginTransition(
+            RemoteTransition launchTransition, RemoteTransition returnTransition)
+            throws RemoteException {
+        if (DEBUG) {
+            Log.d(
+                    TAG,
+                    "makeOriginTransition: (" + launchTransition + ", " + returnTransition + ")");
+        }
+        enforceRemoteTransitionPermission();
+        synchronized (mLock) {
+            OriginTransitionRecord record =
+                    new OriginTransitionRecord(launchTransition, returnTransition);
+            mRecords.put(record.getToken(), record);
+            return record.asLaunchableTransition();
+        }
+    }
+
+    @Override
+    public void cancelOriginTransition(RemoteTransition originTransition) {
+        if (DEBUG) {
+            Log.d(TAG, "cancelOriginTransition: " + originTransition);
+        }
+        enforceRemoteTransitionPermission();
+        synchronized (mLock) {
+            if (!mRecords.containsKey(originTransition.asBinder())) {
+                return;
+            }
+            mRecords.get(originTransition.asBinder()).destroy();
+        }
+    }
+
+    private void enforceRemoteTransitionPermission() {
+        mContext.enforceCallingPermission(
+                Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+                "Missing permission "
+                        + Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS);
+    }
+
+    public void dump(IndentingPrintWriter ipw) {
+        ipw.println("IOriginTransitionsImpl");
+        ipw.println("Active records:");
+        ipw.increaseIndent();
+        synchronized (mLock) {
+            if (mRecords.isEmpty()) {
+                ipw.println("none");
+            } else {
+                for (OriginTransitionRecord record : mRecords.values()) {
+                    record.dump(ipw);
+                }
+            }
+        }
+        ipw.decreaseIndent();
+    }
+
+    /**
+     * An {@link IRemoteTransition} that delegates animation to another {@link IRemoteTransition}
+     * and notify callbacks when the transition starts.
+     */
+    private static class RemoteTransitionDelegate extends IRemoteTransition.Stub {
+        private final IRemoteTransition mTransition;
+        private final Predicate<TransitionInfo> mOnStarting;
+        private final Executor mExecutor;
+
+        RemoteTransitionDelegate(
+                Executor executor,
+                IRemoteTransition transition,
+                Predicate<TransitionInfo> onStarting) {
+            mExecutor = executor;
+            mTransition = transition;
+            mOnStarting = onStarting;
+        }
+
+        @Override
+        public void startAnimation(
+                IBinder token,
+                TransitionInfo info,
+                SurfaceControl.Transaction t,
+                IRemoteTransitionFinishedCallback finishCallback)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "startAnimation: " + info);
+            }
+            if (!mOnStarting.test(info)) {
+                Log.w(TAG, "Skipping cancelled transition " + mTransition);
+                t.addTransactionCommittedListener(
+                                mExecutor,
+                                () -> {
+                                    try {
+                                        finishCallback.onTransitionFinished(null, null);
+                                    } catch (RemoteException e) {
+                                        Log.e(TAG, "Unable to report finish.", e);
+                                    }
+                                })
+                        .apply();
+                return;
+            }
+            mTransition.startAnimation(token, info, t, finishCallback);
+        }
+
+        @Override
+        public void mergeAnimation(
+                IBinder transition,
+                TransitionInfo info,
+                SurfaceControl.Transaction t,
+                IBinder mergeTarget,
+                IRemoteTransitionFinishedCallback finishCallback)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "mergeAnimation: " + info);
+            }
+            mTransition.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+        }
+
+        @Override
+        public void takeOverAnimation(
+                IBinder transition,
+                TransitionInfo info,
+                SurfaceControl.Transaction t,
+                IRemoteTransitionFinishedCallback finishCallback,
+                WindowAnimationState[] states)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "takeOverAnimation: " + info);
+            }
+            mTransition.takeOverAnimation(transition, info, t, finishCallback, states);
+        }
+
+        @Override
+        public void onTransitionConsumed(IBinder transition, boolean aborted)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "onTransitionConsumed: aborted=" + aborted);
+            }
+            mTransition.onTransitionConsumed(transition, aborted);
+        }
+
+        @Override
+        public String toString() {
+            return "RemoteTransitionDelegate{transition=" + mTransition + "}";
+        }
+    }
+
+    /** A data record containing the origin transition pieces. */
+    private class OriginTransitionRecord implements IBinder.DeathRecipient {
+        private final RemoteTransition mWrappedLaunchTransition;
+        private final RemoteTransition mWrappedReturnTransition;
+
+        @GuardedBy("mLock")
+        private boolean mDestroyed;
+
+        OriginTransitionRecord(RemoteTransition launchTransition, RemoteTransition returnTransition)
+                throws RemoteException {
+            mWrappedLaunchTransition = wrap(launchTransition, this::onLaunchTransitionStarting);
+            mWrappedReturnTransition = wrap(returnTransition, this::onReturnTransitionStarting);
+            linkToDeath();
+        }
+
+        private boolean onLaunchTransitionStarting(TransitionInfo info) {
+            synchronized (mLock) {
+                if (mDestroyed) {
+                    return false;
+                }
+                TransitionFilter filter = createFilterForReverseTransition(info);
+                if (filter != null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Registering filter " + filter);
+                    }
+                    mShellTransitions.registerRemote(filter, mWrappedReturnTransition);
+                }
+                return true;
+            }
+        }
+
+        private boolean onReturnTransitionStarting(TransitionInfo info) {
+            synchronized (mLock) {
+                if (mDestroyed) {
+                    return false;
+                }
+                // Clean up stuff.
+                destroy();
+                return true;
+            }
+        }
+
+        public void destroy() {
+            synchronized (mLock) {
+                if (mDestroyed) {
+                    // Already destroyed.
+                    return;
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "Destroying origin transition record " + this);
+                }
+                mDestroyed = true;
+                unlinkToDeath();
+                mShellTransitions.unregisterRemote(mWrappedReturnTransition);
+                mRecords.remove(getToken());
+            }
+        }
+
+        private void linkToDeath() throws RemoteException {
+            asDelegate(mWrappedLaunchTransition).mTransition.asBinder().linkToDeath(this, 0);
+            asDelegate(mWrappedReturnTransition).mTransition.asBinder().linkToDeath(this, 0);
+        }
+
+        private void unlinkToDeath() {
+            asDelegate(mWrappedLaunchTransition).mTransition.asBinder().unlinkToDeath(this, 0);
+            asDelegate(mWrappedReturnTransition).mTransition.asBinder().unlinkToDeath(this, 0);
+        }
+
+        public IBinder getToken() {
+            return asLaunchableTransition().asBinder();
+        }
+
+        public RemoteTransition asLaunchableTransition() {
+            return mWrappedLaunchTransition;
+        }
+
+        @Override
+        public void binderDied() {
+            destroy();
+        }
+
+        @Override
+        public String toString() {
+            return "OriginTransitionRecord{launch="
+                    + mWrappedReturnTransition
+                    + ", return="
+                    + mWrappedReturnTransition
+                    + "}";
+        }
+
+        public void dump(IndentingPrintWriter ipw) {
+            synchronized (mLock) {
+                ipw.println("OriginTransitionRecord");
+                ipw.increaseIndent();
+                ipw.println("mDestroyed: " + mDestroyed);
+                ipw.println("Launch transition:");
+                ipw.increaseIndent();
+                ipw.println(mWrappedLaunchTransition);
+                ipw.decreaseIndent();
+                ipw.println("Return transition:");
+                ipw.increaseIndent();
+                ipw.println(mWrappedReturnTransition);
+                ipw.decreaseIndent();
+                ipw.decreaseIndent();
+            }
+        }
+
+        private static RemoteTransitionDelegate asDelegate(RemoteTransition transition) {
+            return (RemoteTransitionDelegate) transition.getRemoteTransition();
+        }
+
+        private RemoteTransition wrap(
+                RemoteTransition transition, Predicate<TransitionInfo> onStarting) {
+            return new RemoteTransition(
+                    new RemoteTransitionDelegate(
+                            mContext.getMainExecutor(),
+                            transition.getRemoteTransition(),
+                            onStarting),
+                    transition.getDebugName());
+        }
+
+        @Nullable
+        private static TransitionFilter createFilterForReverseTransition(TransitionInfo info) {
+            TaskInfo launchingTaskInfo = null;
+            TaskInfo launchedTaskInfo = null;
+            ComponentName launchingActivity = null;
+            ComponentName launchedActivity = null;
+            for (Change change : info.getChanges()) {
+                int mode = change.getMode();
+                TaskInfo taskInfo = change.getTaskInfo();
+                ComponentName activity = change.getActivityComponent();
+                if (TransitionUtil.isClosingMode(mode)
+                        && launchingTaskInfo == null
+                        && taskInfo != null) {
+                    // Found the launching task!
+                    launchingTaskInfo = taskInfo;
+                } else if (TransitionUtil.isOpeningMode(mode)
+                        && launchedTaskInfo == null
+                        && taskInfo != null) {
+                    // Found the launched task!
+                    launchedTaskInfo = taskInfo;
+                } else if (TransitionUtil.isClosingMode(mode)
+                        && launchingActivity == null
+                        && activity != null) {
+                    // Found the launching activity
+                    launchingActivity = activity;
+                } else if (TransitionUtil.isOpeningMode(mode)
+                        && launchedActivity == null
+                        && activity != null) {
+                    // Found the launched activity!
+                    launchedActivity = activity;
+                }
+            }
+            if (DEBUG) {
+                Log.d(
+                        TAG,
+                        "createFilterForReverseTransition: launchingTaskInfo="
+                                + launchingTaskInfo
+                                + ", launchedTaskInfo="
+                                + launchedTaskInfo
+                                + ", launchingActivity="
+                                + launchedActivity
+                                + ", launchedActivity="
+                                + launchedActivity);
+            }
+            if (launchingTaskInfo == null && launchingActivity == null) {
+                Log.w(
+                        TAG,
+                        "createFilterForReverseTransition: unable to find launching task or"
+                                + " launching activity!");
+                return null;
+            }
+            if (launchedTaskInfo == null && launchedActivity == null) {
+                Log.w(
+                        TAG,
+                        "createFilterForReverseTransition: unable to find launched task or launched"
+                                + " activity!");
+                return null;
+            }
+            if (launchedTaskInfo != null && launchedTaskInfo.launchCookies.isEmpty()) {
+                Log.w(
+                        TAG,
+                        "createFilterForReverseTransition: skipped - launched task has no launch"
+                                + " cookie!");
+                return null;
+            }
+            TransitionFilter filter = new TransitionFilter();
+            filter.mTypeSet = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+
+            // The opening activity of the return transition must match the activity we just closed.
+            TransitionFilter.Requirement req1 = new TransitionFilter.Requirement();
+            req1.mModes = new int[] {TRANSIT_OPEN, TRANSIT_TO_FRONT};
+            req1.mTopActivity =
+                    launchingActivity == null ? launchingTaskInfo.topActivity : launchingActivity;
+
+            TransitionFilter.Requirement req2 = new TransitionFilter.Requirement();
+            req2.mModes = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+            if (launchedTaskInfo != null) {
+                // For task transitions, the closing task's cookie must match the task we just
+                // launched.
+                req2.mLaunchCookie = launchedTaskInfo.launchCookies.get(0);
+            } else {
+                // For activity transitions, the closing activity of the return transition must
+                // match
+                // the activity we just launched.
+                req2.mTopActivity = launchedActivity;
+            }
+
+            filter.mRequirements = new TransitionFilter.Requirement[] {req1, req2};
+            return filter;
+        }
+    }
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/shared/IOriginTransitions.aidl b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/shared/IOriginTransitions.aidl
new file mode 100644
index 0000000..31cca70
--- /dev/null
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/shared/IOriginTransitions.aidl
@@ -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.systemui.animation.shared;
+
+import android.window.RemoteTransition;
+
+/**
+ * An interface for an app to link a launch transition and a return transition together into an
+ * origin transition.
+ */
+interface IOriginTransitions {
+
+    /**
+     * Create a new "origin transition" which wraps a launch transition and a return transition.
+     * The returned {@link RemoteTransition} is expected to be passed to
+     * {@link ActivityOptions#makeRemoteTransition(RemoteTransition)} to create an
+     * {@link ActivityOptions} and being used to launch an intent. When being used with
+     * {@link ActivityOptions}, the launch transition will be triggered for launching the intent,
+     * and the return transition will be remembered and triggered for returning from the launched
+     * activity.
+     */
+    RemoteTransition makeOriginTransition(in RemoteTransition launchTransition,
+            in RemoteTransition returnTransition) = 1;
+
+    /**
+     * Cancels an origin transition. Any parts not yet played will no longer be triggered, and the
+     * origin transition object will reset to a single frame animation.
+     */
+    void cancelOriginTransition(in RemoteTransition originTransition) = 2;
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index c14ee62..9d0b095 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -55,6 +55,7 @@
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.systemui.Flags.activityTransitionUseLargestWindow
 import com.android.systemui.Flags.translucentOccludingActivityFix
+import com.android.systemui.animation.TransitionAnimator.Companion.toTransitionState
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
 import com.android.wm.shell.shared.IShellTransitions
 import com.android.wm.shell.shared.ShellTransitions
@@ -130,7 +131,7 @@
                 contentBeforeFadeOutDelay = 0L,
                 contentBeforeFadeOutDuration = 150L,
                 contentAfterFadeInDelay = 150L,
-                contentAfterFadeInDuration = 183L
+                contentAfterFadeInDuration = 183L,
             )
 
         /**
@@ -147,7 +148,7 @@
                 positionInterpolator = Interpolators.EMPHASIZED,
                 positionXInterpolator = Interpolators.EMPHASIZED_COMPLEMENT,
                 contentBeforeFadeOutInterpolator = Interpolators.LINEAR_OUT_SLOW_IN,
-                contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f)
+                contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f),
             )
 
         // TODO(b/288507023): Remove this flag.
@@ -238,7 +239,7 @@
         animate: Boolean = true,
         packageName: String? = null,
         showOverLockscreen: Boolean = false,
-        intentStarter: (RemoteAnimationAdapter?) -> Int
+        intentStarter: (RemoteAnimationAdapter?) -> Int,
     ) {
         if (controller == null || !animate) {
             Log.i(TAG, "Starting intent with no animation")
@@ -263,7 +264,7 @@
                 RemoteAnimationAdapter(
                     runner,
                     TIMINGS.totalDuration,
-                    TIMINGS.totalDuration - 150 /* statusBarTransitionDelay */
+                    TIMINGS.totalDuration - 150, /* statusBarTransitionDelay */
                 )
             } else {
                 null
@@ -277,7 +278,7 @@
                     .registerRemoteAnimationForNextActivityStart(
                         packageName,
                         animationAdapter,
-                        null /* launchCookie */
+                        null, /* launchCookie */
                     )
             } catch (e: RemoteException) {
                 Log.w(TAG, "Unable to register the remote animation", e)
@@ -301,7 +302,7 @@
         Log.i(
             TAG,
             "launchResult=$launchResult willAnimate=$willAnimate " +
-                "hideKeyguardWithAnimation=$hideKeyguardWithAnimation"
+                "hideKeyguardWithAnimation=$hideKeyguardWithAnimation",
         )
         controller.callOnIntentStartedOnMainThread(willAnimate)
 
@@ -328,7 +329,7 @@
                 Log.d(
                     TAG,
                     "Calling controller.onIntentStarted(willAnimate=$willAnimate) " +
-                        "[controller=$this]"
+                        "[controller=$this]",
                 )
             }
             this.onIntentStarted(willAnimate)
@@ -350,7 +351,7 @@
         animate: Boolean = true,
         packageName: String? = null,
         showOverLockscreen: Boolean = false,
-        intentStarter: PendingIntentStarter
+        intentStarter: PendingIntentStarter,
     ) {
         startIntentWithAnimation(controller, animate, packageName, showOverLockscreen) {
             intentStarter.startPendingIntent(it)
@@ -366,7 +367,7 @@
      */
     private fun registerEphemeralReturnAnimation(
         launchController: Controller,
-        transitionRegister: TransitionRegister?
+        transitionRegister: TransitionRegister?,
     ) {
         if (!returnAnimationFrameworkLibrary()) return
 
@@ -410,7 +411,7 @@
         val transition =
             RemoteTransition(
                 RemoteAnimationRunnerCompat.wrap(returnRunner),
-                "${launchController.transitionCookie}_returnTransition"
+                "${launchController.transitionCookie}_returnTransition",
             )
 
         transitionRegister?.register(filter, transition)
@@ -508,7 +509,7 @@
                 cujType: Int? = null,
                 cookie: TransitionCookie? = null,
                 component: ComponentName? = null,
-                returnCujType: Int? = null
+                returnCujType: Int? = null,
             ): Controller? {
                 // Make sure the View we launch from implements LaunchableView to avoid visibility
                 // issues.
@@ -525,7 +526,7 @@
                     Log.e(
                         TAG,
                         "Skipping animation as view $view is not attached to a ViewGroup",
-                        Exception()
+                        Exception(),
                     )
                     return null
                 }
@@ -535,7 +536,7 @@
                     cujType,
                     cookie,
                     component,
-                    returnCujType
+                    returnCujType,
                 )
             }
         }
@@ -646,7 +647,7 @@
         val launchRemoteTransition =
             RemoteTransition(
                 RemoteAnimationRunnerCompat.wrap(createRunner(controller)),
-                "${cookie}_launchTransition"
+                "${cookie}_launchTransition",
             )
         transitionRegister.register(launchFilter, launchRemoteTransition)
 
@@ -668,7 +669,7 @@
         val returnRemoteTransition =
             RemoteTransition(
                 RemoteAnimationRunnerCompat.wrap(createRunner(returnController)),
-                "${cookie}_returnTransition"
+                "${cookie}_returnTransition",
             )
         transitionRegister.register(returnFilter, returnRemoteTransition)
 
@@ -690,7 +691,7 @@
     @VisibleForTesting
     inner class DelegatingAnimationCompletionListener(
         private val delegate: Listener?,
-        private val onAnimationComplete: () -> Unit
+        private val onAnimationComplete: () -> Unit,
     ) : Listener {
         var cancelled = false
 
@@ -723,7 +724,7 @@
         /** The animator to use to animate the window transition. */
         transitionAnimator: TransitionAnimator,
         /** Listener for animation lifecycle events. */
-        listener: Listener? = null
+        listener: Listener? = null,
     ) : IRemoteAnimationRunner.Stub() {
         // This is being passed across IPC boundaries and cycles (through PendingIntentRecords,
         // etc.) are possible. So we need to make sure we drop any references that might
@@ -748,7 +749,7 @@
             apps: Array<out RemoteAnimationTarget>?,
             wallpapers: Array<out RemoteAnimationTarget>?,
             nonApps: Array<out RemoteAnimationTarget>?,
-            finishedCallback: IRemoteAnimationFinishedCallback?
+            finishedCallback: IRemoteAnimationFinishedCallback?,
         ) {
             val delegate = delegate
             mainExecutor.execute {
@@ -838,7 +839,7 @@
             Log.wtf(
                 TAG,
                 "The remote animation was neither cancelled or started within " +
-                    "$LONG_TRANSITION_TIMEOUT"
+                    "$LONG_TRANSITION_TIMEOUT",
             )
         }
 
@@ -869,7 +870,7 @@
             apps: Array<out RemoteAnimationTarget>?,
             wallpapers: Array<out RemoteAnimationTarget>?,
             nonApps: Array<out RemoteAnimationTarget>?,
-            callback: IRemoteAnimationFinishedCallback?
+            callback: IRemoteAnimationFinishedCallback?,
         ) {
             removeTimeouts()
 
@@ -894,7 +895,7 @@
                 if (DEBUG_TRANSITION_ANIMATION) {
                     Log.d(
                         TAG,
-                        "Calling controller.onTransitionAnimationCancelled() [no window opening]"
+                        "Calling controller.onTransitionAnimationCancelled() [no window opening]",
                     )
                 }
                 controller.onTransitionAnimationCancelled()
@@ -974,7 +975,7 @@
         private fun startAnimation(
             window: RemoteAnimationTarget,
             navigationBar: RemoteAnimationTarget?,
-            iCallback: IRemoteAnimationFinishedCallback?
+            iCallback: IRemoteAnimationFinishedCallback?,
         ) {
             if (TransitionAnimator.DEBUG) {
                 Log.d(TAG, "Remote animation started")
@@ -983,12 +984,28 @@
             val windowBounds = window.screenSpaceBounds
             val endState =
                 if (controller.isLaunching) {
-                    TransitionAnimator.State(
-                        top = windowBounds.top,
-                        bottom = windowBounds.bottom,
-                        left = windowBounds.left,
-                        right = windowBounds.right
-                    )
+                    controller.windowAnimatorState?.toTransitionState()
+                        ?: TransitionAnimator.State(
+                                top = windowBounds.top,
+                                bottom = windowBounds.bottom,
+                                left = windowBounds.left,
+                                right = windowBounds.right,
+                            )
+                            .apply {
+                                // TODO(b/184121838): We should somehow get the top and bottom
+                                // radius of the window instead of recomputing isExpandingFullyAbove
+                                // here.
+                                getWindowRadius(
+                                        transitionAnimator.isExpandingFullyAbove(
+                                            controller.transitionContainer,
+                                            this,
+                                        )
+                                    )
+                                    .let {
+                                        topCornerRadius = it
+                                        bottomCornerRadius = it
+                                    }
+                            }
                 } else {
                     controller.createAnimatorState()
                 }
@@ -1000,15 +1017,8 @@
                         ?: window.backgroundColor
                 }
 
-            // TODO(b/184121838): We should somehow get the top and bottom radius of the window
-            // instead of recomputing isExpandingFullyAbove here.
             val isExpandingFullyAbove =
                 transitionAnimator.isExpandingFullyAbove(controller.transitionContainer, endState)
-            if (controller.isLaunching) {
-                val endRadius = getWindowRadius(isExpandingFullyAbove)
-                endState.topCornerRadius = endRadius
-                endState.bottomCornerRadius = endRadius
-            }
 
             // We animate the opening window and delegate the view expansion to [this.controller].
             val delegate = this.controller
@@ -1016,15 +1026,17 @@
                 object : Controller by delegate {
                     override fun createAnimatorState(): TransitionAnimator.State {
                         if (isLaunching) return delegate.createAnimatorState()
-                        val windowRadius = getWindowRadius(isExpandingFullyAbove)
-                        return TransitionAnimator.State(
-                            top = windowBounds.top,
-                            bottom = windowBounds.bottom,
-                            left = windowBounds.left,
-                            right = windowBounds.right,
-                            topCornerRadius = windowRadius,
-                            bottomCornerRadius = windowRadius
-                        )
+                        return delegate.windowAnimatorState?.toTransitionState()
+                            ?: getWindowRadius(isExpandingFullyAbove).let {
+                                TransitionAnimator.State(
+                                    top = windowBounds.top,
+                                    bottom = windowBounds.bottom,
+                                    left = windowBounds.left,
+                                    right = windowBounds.right,
+                                    topCornerRadius = it,
+                                    bottomCornerRadius = it,
+                                )
+                            }
                     }
 
                     override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -1035,7 +1047,7 @@
                                 TAG,
                                 "Calling controller.onTransitionAnimationStart(" +
                                     "isExpandingFullyAbove=$isExpandingFullyAbove) " +
-                                    "[controller=$delegate]"
+                                    "[controller=$delegate]",
                             )
                         }
                         delegate.onTransitionAnimationStart(isExpandingFullyAbove)
@@ -1050,7 +1062,7 @@
                                 TAG,
                                 "Calling controller.onTransitionAnimationEnd(" +
                                     "isExpandingFullyAbove=$isExpandingFullyAbove) " +
-                                    "[controller=$delegate]"
+                                    "[controller=$delegate]",
                             )
                         }
                         delegate.onTransitionAnimationEnd(isExpandingFullyAbove)
@@ -1059,7 +1071,7 @@
                     override fun onTransitionAnimationProgress(
                         state: TransitionAnimator.State,
                         progress: Float,
-                        linearProgress: Float
+                        linearProgress: Float,
                     ) {
                         applyStateToWindow(window, state, linearProgress)
                         navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
@@ -1135,7 +1147,7 @@
                 windowCropF.left.roundToInt(),
                 windowCropF.top.roundToInt(),
                 windowCropF.right.roundToInt(),
-                windowCropF.bottom.roundToInt()
+                windowCropF.bottom.roundToInt(),
             )
 
             val windowAnimationDelay =
@@ -1155,7 +1167,7 @@
                     TIMINGS,
                     linearProgress,
                     windowAnimationDelay,
-                    windowAnimationDuration
+                    windowAnimationDuration,
                 )
 
             // The alpha of the opening window. If it opens above the expandable, then it should
@@ -1198,7 +1210,7 @@
         private fun applyStateToNavigationBar(
             navigationBar: RemoteAnimationTarget,
             state: TransitionAnimator.State,
-            linearProgress: Float
+            linearProgress: Float,
         ) {
             if (transactionApplierView.viewRootImpl == null || !navigationBar.leash.isValid) {
                 // Don't apply any transaction if the view root we synchronize with was detached or
@@ -1212,7 +1224,7 @@
                     TIMINGS,
                     linearProgress,
                     ANIMATION_DELAY_NAV_FADE_IN,
-                    ANIMATION_DURATION_NAV_FADE_OUT
+                    ANIMATION_DURATION_NAV_FADE_OUT,
                 )
 
             val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
@@ -1220,7 +1232,7 @@
                 matrix.reset()
                 matrix.setTranslate(
                     0f,
-                    (state.top - navigationBar.sourceContainerBounds.top).toFloat()
+                    (state.top - navigationBar.sourceContainerBounds.top).toFloat(),
                 )
                 windowCrop.set(state.left, 0, state.right, state.height)
                 params
@@ -1234,7 +1246,7 @@
                         TIMINGS,
                         linearProgress,
                         0,
-                        ANIMATION_DURATION_NAV_FADE_OUT
+                        ANIMATION_DURATION_NAV_FADE_OUT,
                     )
                 params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
             }
@@ -1255,7 +1267,7 @@
             if (DEBUG_TRANSITION_ANIMATION) {
                 Log.d(
                     TAG,
-                    "Calling controller.onTransitionAnimationCancelled() [animation timed out]"
+                    "Calling controller.onTransitionAnimationCancelled() [animation timed out]",
                 )
             }
             controller.onTransitionAnimationCancelled()
@@ -1329,10 +1341,7 @@
         }
 
         /** Register [remoteTransition] with WM Shell using the given [filter]. */
-        internal fun register(
-            filter: TransitionFilter,
-            remoteTransition: RemoteTransition,
-        ) {
+        internal fun register(filter: TransitionFilter, remoteTransition: RemoteTransition) {
             shellTransitions?.registerRemote(filter, remoteTransition)
             iShellTransitions?.registerRemote(filter, remoteTransition)
         }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index 8e824e6..fc4cf1d 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -28,6 +28,7 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.animation.Interpolator
+import android.window.WindowAnimationState
 import androidx.annotation.VisibleForTesting
 import com.android.app.animation.Interpolators.LINEAR
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
@@ -56,12 +57,12 @@
             timings: Timings,
             linearProgress: Float,
             delay: Long,
-            duration: Long
+            duration: Long,
         ): Float {
             return MathUtils.constrain(
                 (linearProgress * timings.totalDuration - delay) / duration,
                 0.0f,
-                1.0f
+                1.0f,
             )
         }
 
@@ -71,6 +72,18 @@
                     "disabled"
             }
         }
+
+        internal fun WindowAnimationState.toTransitionState() =
+            State().also {
+                bounds?.let { b ->
+                    it.top = b.top.roundToInt()
+                    it.left = b.left.roundToInt()
+                    it.bottom = b.bottom.roundToInt()
+                    it.right = b.right.roundToInt()
+                }
+                it.bottomCornerRadius = (bottomLeftRadius + bottomRightRadius) / 2
+                it.topCornerRadius = (topLeftRadius + topRightRadius) / 2
+            }
     }
 
     private val transitionContainerLocation = IntArray(2)
@@ -117,6 +130,15 @@
             get() = null
 
         /**
+         * Window state for the animation. If [isLaunching], it would correspond to the end state
+         * otherwise the start state.
+         *
+         * If null, the state is inferred from the window targets
+         */
+        val windowAnimatorState: WindowAnimationState?
+            get() = null
+
+        /**
          * Return the [State] of the view that will be animated. We will animate from this state to
          * the final window state.
          *
@@ -151,7 +173,7 @@
         var left: Int = 0,
         var right: Int = 0,
         var topCornerRadius: Float = 0f,
-        var bottomCornerRadius: Float = 0f
+        var bottomCornerRadius: Float = 0f,
     ) {
         private val startTop = top
 
@@ -197,7 +219,7 @@
         val contentAfterFadeInDelay: Long,
 
         /** The duration of the expanded content fade in. */
-        val contentAfterFadeInDuration: Long
+        val contentAfterFadeInDuration: Long,
     )
 
     /** The interpolators used by this animator. */
@@ -215,7 +237,7 @@
         val contentBeforeFadeOutInterpolator: Interpolator,
 
         /** The interpolator used when fading in the expanded content. */
-        val contentAfterFadeInInterpolator: Interpolator
+        val contentAfterFadeInInterpolator: Interpolator,
     )
 
     /**
@@ -254,7 +276,7 @@
                 endState,
                 windowBackgroundLayer,
                 fadeWindowBackgroundLayer,
-                drawHole
+                drawHole,
             )
         animator.start()
 
@@ -271,7 +293,7 @@
         endState: State,
         windowBackgroundLayer: GradientDrawable,
         fadeWindowBackgroundLayer: Boolean = true,
-        drawHole: Boolean = false
+        drawHole: Boolean = false,
     ): ValueAnimator {
         val state = controller.createAnimatorState()
 
@@ -399,14 +421,14 @@
                         timings,
                         linearProgress,
                         timings.contentBeforeFadeOutDelay,
-                        timings.contentBeforeFadeOutDuration
+                        timings.contentBeforeFadeOutDuration,
                     ) < 1
                 } else {
                     getProgress(
                         timings,
                         linearProgress,
                         timings.contentAfterFadeInDelay,
-                        timings.contentAfterFadeInDuration
+                        timings.contentAfterFadeInDuration,
                     ) > 0
                 }
 
@@ -427,7 +449,7 @@
                 ViewRootSync.synchronizeNextDraw(
                     transitionContainer,
                     openingWindowSyncView,
-                    then = {}
+                    then = {},
                 )
             } else if (
                 !controller.isLaunching &&
@@ -446,7 +468,7 @@
                 ViewRootSync.synchronizeNextDraw(
                     openingWindowSyncView,
                     transitionContainer,
-                    then = {}
+                    then = {},
                 )
             }
 
@@ -464,7 +486,7 @@
                 container,
                 fadeWindowBackgroundLayer,
                 drawHole,
-                controller.isLaunching
+                controller.isLaunching,
             )
             controller.onTransitionAnimationProgress(state, progress, linearProgress)
         }
@@ -488,7 +510,7 @@
         transitionContainer: View,
         fadeWindowBackgroundLayer: Boolean,
         drawHole: Boolean,
-        isLaunching: Boolean
+        isLaunching: Boolean,
     ) {
         // Update position.
         transitionContainer.getLocationOnScreen(transitionContainerLocation)
@@ -496,7 +518,7 @@
             state.left - transitionContainerLocation[0],
             state.top - transitionContainerLocation[1],
             state.right - transitionContainerLocation[0],
-            state.bottom - transitionContainerLocation[1]
+            state.bottom - transitionContainerLocation[1],
         )
 
         // Update radius.
@@ -517,7 +539,7 @@
                 timings,
                 linearProgress,
                 timings.contentBeforeFadeOutDelay,
-                timings.contentBeforeFadeOutDuration
+                timings.contentBeforeFadeOutDuration,
             )
 
         if (isLaunching) {
@@ -531,7 +553,7 @@
                         timings,
                         linearProgress,
                         timings.contentAfterFadeInDelay,
-                        timings.contentAfterFadeInDuration
+                        timings.contentAfterFadeInDuration,
                     )
                 val alpha =
                     1 -
@@ -561,7 +583,7 @@
                         timings,
                         linearProgress,
                         timings.contentAfterFadeInDelay,
-                        timings.contentAfterFadeInDuration
+                        timings.contentAfterFadeInDuration,
                     )
                 val alpha =
                     1 -
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index 34eafde..d326f00 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -830,7 +830,7 @@
             Image(
                 bitmap = it.asImageBitmap(),
                 contentDescription = null,
-                modifier = Modifier.size(SelectedUserImageSize),
+                modifier = Modifier.size(SelectedUserImageSize).sysuiResTag("user_icon"),
             )
         }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 480e4e4..489e24e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.bouncer.ui.composable
 
 import android.view.HapticFeedbackConstants
+import android.view.MotionEvent
 import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationSpec
@@ -49,6 +50,7 @@
 import androidx.compose.ui.geometry.CornerRadius
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInteropFilter
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -61,6 +63,7 @@
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.res.R
 import kotlin.time.Duration.Companion.milliseconds
 import kotlin.time.DurationUnit
@@ -101,7 +104,7 @@
         columns = columns,
         verticalSpacing = verticalSpacing,
         horizontalSpacing = calculateHorizontalSpacingBetweenColumns(gridWidth = 300.dp),
-        modifier = modifier.focusRequester(focusRequester)
+        modifier = modifier.focusRequester(focusRequester).sysuiResTag("pin_pad_grid")
     ) {
         repeat(9) { index ->
             DigitButton(
@@ -110,6 +113,7 @@
                 onClicked = viewModel::onPinButtonClicked,
                 scaling = buttonScaleAnimatables[index]::value,
                 isAnimationEnabled = isDigitButtonAnimationEnabled,
+                onPointerDown = viewModel::onDigitButtonDown,
             )
         }
 
@@ -125,6 +129,7 @@
             onLongPressed = viewModel::onBackspaceButtonLongPressed,
             appearance = backspaceButtonAppearance,
             scaling = buttonScaleAnimatables[9]::value,
+            elementId = "delete_button"
         )
 
         DigitButton(
@@ -133,6 +138,7 @@
             onClicked = viewModel::onPinButtonClicked,
             scaling = buttonScaleAnimatables[10]::value,
             isAnimationEnabled = isDigitButtonAnimationEnabled,
+            onPointerDown = viewModel::onDigitButtonDown
         )
 
         ActionButton(
@@ -146,6 +152,7 @@
             onClicked = viewModel::onAuthenticateButtonClicked,
             appearance = confirmButtonAppearance,
             scaling = buttonScaleAnimatables[11]::value,
+            elementId = "key_enter"
         )
     }
 }
@@ -155,6 +162,7 @@
     digit: Int,
     isInputEnabled: Boolean,
     onClicked: (Int) -> Unit,
+    onPointerDown: () -> Unit,
     scaling: () -> Float,
     isAnimationEnabled: Boolean,
 ) {
@@ -164,6 +172,7 @@
         backgroundColor = MaterialTheme.colorScheme.surfaceVariant,
         foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant,
         isAnimationEnabled = isAnimationEnabled,
+        onPointerDown = onPointerDown,
         modifier =
             Modifier.graphicsLayer {
                 val scale = if (isAnimationEnabled) scaling() else 1f
@@ -186,6 +195,7 @@
     icon: Icon,
     isInputEnabled: Boolean,
     onClicked: () -> Unit,
+    elementId: String,
     onLongPressed: (() -> Unit)? = null,
     appearance: ActionButtonAppearance,
     scaling: () -> Float,
@@ -211,6 +221,7 @@
         backgroundColor = backgroundColor,
         foregroundColor = foregroundColor,
         isAnimationEnabled = true,
+        elementId = elementId,
         modifier =
             Modifier.graphicsLayer {
                 alpha = hiddenAlpha
@@ -234,7 +245,9 @@
     foregroundColor: Color,
     isAnimationEnabled: Boolean,
     modifier: Modifier = Modifier,
+    elementId: String? = null,
     onLongPressed: (() -> Unit)? = null,
+    onPointerDown: (() -> Unit)? = null,
     content: @Composable (contentColor: () -> Color) -> Unit,
 ) {
     val interactionSource = remember { MutableInteractionSource() }
@@ -303,12 +316,19 @@
                 .clip(CircleShape)
                 .thenIf(isEnabled) {
                     Modifier.combinedClickable(
-                        interactionSource = interactionSource,
-                        indication = indication,
-                        onClick = onClicked,
-                        onLongClick = onLongPressed
-                    )
-                },
+                            interactionSource = interactionSource,
+                            indication = indication,
+                            onClick = onClicked,
+                            onLongClick = onLongPressed
+                        )
+                        .pointerInteropFilter { motionEvent ->
+                            if (motionEvent.action == MotionEvent.ACTION_DOWN) {
+                                onPointerDown?.let { it() }
+                            }
+                            false
+                        }
+                }
+                .thenIf(elementId != null) { Modifier.sysuiResTag(elementId!!) },
     ) {
         content(contentColor::value)
     }
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 d34295e..fa92bef34 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
@@ -64,6 +64,7 @@
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLifecycleOwner
 import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -146,9 +147,7 @@
     }
 
     @Composable
-    override fun SceneScope.Content(
-        modifier: Modifier,
-    ) {
+    override fun SceneScope.Content(modifier: Modifier) {
         QuickSettingsScene(
             notificationStackScrollView = notificationStackScrollView.get(),
             viewModelFactory = contentViewModelFactory,
@@ -199,13 +198,17 @@
         onDispose { notificationsPlaceholderViewModel.setAlphaForBrightnessMirror(1f) }
     }
 
+    val shadeHorizontalPadding =
+        dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
+
     BrightnessMirror(
         viewModel = brightnessMirrorViewModel,
         qsSceneAdapter = viewModel.qsSceneAdapter,
         modifier =
             Modifier.thenIf(cutoutLocation != CutoutLocation.CENTER) {
-                Modifier.displayCutoutPadding()
-            }
+                    Modifier.displayCutoutPadding()
+                }
+                .padding(horizontal = shadeHorizontalPadding),
     )
 
     val shouldPunchHoleBehindScrim =
@@ -224,9 +227,7 @@
                     // scene (and not the one under it) during a scene transition.
                     Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
                 }
-                .thenIf(cutoutLocation != CutoutLocation.CENTER) {
-                    Modifier.displayCutoutPadding()
-                },
+                .thenIf(cutoutLocation != CutoutLocation.CENTER) { Modifier.displayCutoutPadding() }
     ) {
         val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle()
         val isCustomizerShowing by
@@ -235,11 +236,7 @@
             viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle()
         val screenHeight = LocalRawScreenHeight.current
 
-        BackHandler(
-            enabled = isCustomizing,
-        ) {
-            viewModel.qsSceneAdapter.requestCloseCustomizer()
-        }
+        BackHandler(enabled = isCustomizing) { viewModel.qsSceneAdapter.requestCloseCustomizer() }
 
         val collapsedHeaderHeight =
             with(LocalDensity.current) { ShadeHeader.Dimensions.CollapsedHeight.roundToPx() }
@@ -276,13 +273,13 @@
             animateDpAsState(
                 targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
                 animationSpec = tween(customizingAnimationDuration),
-                label = "animateQSSceneBottomPaddingAsState"
+                label = "animateQSSceneBottomPaddingAsState",
             )
         val topPadding by
             animateDpAsState(
                 targetValue = if (isCustomizing) ShadeHeader.Dimensions.CollapsedHeight else 0.dp,
                 animationSpec = tween(customizingAnimationDuration),
-                label = "animateQSSceneTopPaddingAsState"
+                label = "animateQSSceneTopPaddingAsState",
             )
 
         LaunchedEffect(navBarBottomHeight, density) {
@@ -313,18 +310,15 @@
                 Modifier.fillMaxSize()
                     .padding(
                         top = topPadding.coerceAtLeast(0.dp),
-                        bottom = bottomPadding.coerceAtLeast(0.dp)
-                    )
+                        bottom = bottomPadding.coerceAtLeast(0.dp),
+                    ),
         ) {
             Box(modifier = Modifier.fillMaxSize().weight(1f)) {
                 val shadeHeaderAndQuickSettingsModifier =
                     if (isCustomizerShowing) {
                         Modifier.fillMaxHeight().align(Alignment.TopCenter)
                     } else {
-                        Modifier.verticalScroll(
-                                scrollState,
-                                enabled = isScrollable,
-                            )
+                        Modifier.verticalScroll(scrollState, enabled = isScrollable)
                             .clipScrollableContainer(Orientation.Horizontal)
                             .fillMaxWidth()
                             .wrapContentHeight(unbounded = true)
@@ -333,7 +327,7 @@
 
                 Column(
                     modifier =
-                        shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view"),
+                        shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view")
                 ) {
                     when (LocalWindowSizeClass.current.widthSizeClass) {
                         WindowWidthSizeClass.Compact ->
@@ -345,7 +339,7 @@
                                         expandFrom = Alignment.Top,
                                     ) +
                                         slideInVertically(
-                                            animationSpec = tween(customizingAnimationDuration),
+                                            animationSpec = tween(customizingAnimationDuration)
                                         ) +
                                         fadeIn(tween(customizingAnimationDuration)),
                                 exit =
@@ -354,7 +348,7 @@
                                         shrinkTowards = Alignment.Top,
                                     ) +
                                         slideOutVertically(
-                                            animationSpec = tween(customizingAnimationDuration),
+                                            animationSpec = tween(customizingAnimationDuration)
                                         ) +
                                         fadeOut(tween(customizingAnimationDuration)),
                             ) {
@@ -382,7 +376,7 @@
                             viewModel.qsSceneAdapter,
                             { viewModel.qsSceneAdapter.qsHeight },
                             isSplitShade = false,
-                            modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS)
+                            modifier = Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.QS),
                         )
 
                         MediaCarousel(
@@ -400,13 +394,12 @@
                             { mediaOffset.roundToPx() },
                         )
                     }
-                    if (mediaInRow) {
-                        Layout(
-                            content = content,
-                            measurePolicy = landscapeQsMediaMeasurePolicy,
-                        )
-                    } else {
-                        content()
+                    Box(modifier = Modifier.padding(horizontal = shadeHorizontalPadding)) {
+                        if (mediaInRow) {
+                            Layout(content = content, measurePolicy = landscapeQsMediaMeasurePolicy)
+                        } else {
+                            content()
+                        }
                     }
                 }
             }
@@ -417,13 +410,18 @@
                 customizingAnimationDuration = customizingAnimationDuration,
                 lifecycleOwner = lifecycleOwner,
                 modifier =
-                    Modifier.align(Alignment.CenterHorizontally).sysuiResTag("qs_footer_actions"),
+                    Modifier.align(Alignment.CenterHorizontally)
+                        .sysuiResTag("qs_footer_actions")
+                        .padding(horizontal = shadeHorizontalPadding),
             )
         }
         HeadsUpNotificationSpace(
             stackScrollView = notificationStackScrollView,
             viewModel = notificationsPlaceholderViewModel,
-            modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),
+            modifier =
+                Modifier.align(Alignment.BottomCenter)
+                    .navigationBarsPadding()
+                    .padding(horizontal = shadeHorizontalPadding),
             isPeekFromBottom = true,
         )
         NotificationScrollingStack(
@@ -435,15 +433,18 @@
             shouldIncludeHeadsUpSpace = false,
             shadeMode = ShadeMode.Single,
             modifier =
-                Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) },
+                Modifier.fillMaxWidth()
+                    .offset { IntOffset(x = 0, y = screenHeight.roundToInt()) }
+                    .padding(horizontal = shadeHorizontalPadding),
         )
         NotificationStackCutoffGuideline(
             stackScrollView = notificationStackScrollView,
             viewModel = notificationsPlaceholderViewModel,
             modifier =
-                Modifier.align(Alignment.BottomCenter).navigationBarsPadding().offset {
-                    IntOffset(x = 0, y = screenHeight.roundToInt())
-                }
+                Modifier.align(Alignment.BottomCenter)
+                    .navigationBarsPadding()
+                    .offset { IntOffset(x = 0, y = screenHeight.roundToInt()) }
+                    .padding(horizontal = shadeHorizontalPadding),
         )
     }
 }
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 5a084db..ebe1df4 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
@@ -813,6 +813,10 @@
     element: Element,
     elementState: TransitionState,
 ): Boolean {
+    if (element.key.placeAllCopies) {
+        return true
+    }
+
     val transition =
         when (elementState) {
             is TransitionState.Idle -> {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
index f9a9eeb..2e7488b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
@@ -79,6 +79,16 @@
      * or compose MovableElements.
      */
     open val contentPicker: ElementContentPicker = DefaultElementContentPicker,
+
+    /**
+     * Whether we should place all copies of this element when it is shared.
+     *
+     * This should usually be false, but it can be useful when sharing a container that has a
+     * different content in different scenes/overlays. That way the container will have the same
+     * size and position in all scenes/overlays but all different contents will be placed and
+     * visible on screen.
+     */
+    val placeAllCopies: Boolean = false,
 ) : Key(debugName, identity), ElementMatcher {
     @VisibleForTesting
     // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index 1f26b71..6a5b7e1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -37,7 +37,7 @@
     modifier: Modifier,
     content: @Composable ElementScope<ElementContentScope>.() -> Unit,
 ) {
-    Box(modifier.element(layoutImpl, sceneOrOverlay, key)) {
+    Box(modifier.element(layoutImpl, sceneOrOverlay, key), propagateMinConstraints = true) {
         val contentScope = sceneOrOverlay.scope
         val boxScope = this
         val elementScope =
@@ -64,7 +64,7 @@
             "MovableElementKey($elementName).contentPicker.contents does not contain $contentName"
     }
 
-    Box(modifier.element(layoutImpl, sceneOrOverlay, key)) {
+    Box(modifier.element(layoutImpl, sceneOrOverlay, key), propagateMinConstraints = true) {
         val contentScope = sceneOrOverlay.scope
         val boxScope = this
         val elementScope =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 30eb302..077927d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -50,7 +50,8 @@
     fun currentOverlays(): Flow<Set<OverlayKey>> {
         return when (this) {
             is Idle -> flowOf(currentOverlays)
-            is Transition -> currentOverlays
+            is Transition.ChangeScene -> flowOf(currentOverlays)
+            is Transition.OverlayTransition -> currentOverlays
         }
     }
 
@@ -64,7 +65,6 @@
     sealed class Transition(
         val fromContent: ContentKey,
         val toContent: ContentKey,
-        val currentOverlays: Flow<Set<OverlayKey>>,
         val progress: Flow<Float>,
 
         /**
@@ -105,7 +105,7 @@
             val fromScene: SceneKey,
             val toScene: SceneKey,
             val currentScene: Flow<SceneKey>,
-            currentOverlays: Set<OverlayKey>,
+            val currentOverlays: Set<OverlayKey>,
             progress: Flow<Float>,
             isInitiatedByUserInput: Boolean,
             isUserInputOngoing: Flow<Boolean>,
@@ -115,7 +115,31 @@
             Transition(
                 fromScene,
                 toScene,
-                flowOf(currentOverlays),
+                progress,
+                isInitiatedByUserInput,
+                isUserInputOngoing,
+                previewProgress,
+                isInPreviewStage,
+            )
+
+        /**
+         * A transition that is animating one or more overlays and for which [currentOverlays] will
+         * change over the course of the transition.
+         */
+        sealed class OverlayTransition(
+            fromContent: ContentKey,
+            toContent: ContentKey,
+            val currentScene: SceneKey,
+            val currentOverlays: Flow<Set<OverlayKey>>,
+            progress: Flow<Float>,
+            isInitiatedByUserInput: Boolean,
+            isUserInputOngoing: Flow<Boolean>,
+            previewProgress: Flow<Float>,
+            isInPreviewStage: Flow<Boolean>,
+        ) :
+            Transition(
+                fromContent,
+                toContent,
                 progress,
                 isInitiatedByUserInput,
                 isUserInputOngoing,
@@ -128,7 +152,7 @@
             val overlay: OverlayKey,
             fromContent: ContentKey,
             toContent: ContentKey,
-            val currentScene: SceneKey,
+            currentScene: SceneKey,
             currentOverlays: Flow<Set<OverlayKey>>,
             progress: Flow<Float>,
             isInitiatedByUserInput: Boolean,
@@ -136,9 +160,10 @@
             previewProgress: Flow<Float>,
             isInPreviewStage: Flow<Boolean>,
         ) :
-            Transition(
+            OverlayTransition(
                 fromContent,
                 toContent,
+                currentScene,
                 currentOverlays,
                 progress,
                 isInitiatedByUserInput,
@@ -151,7 +176,7 @@
         class ReplaceOverlay(
             val fromOverlay: OverlayKey,
             val toOverlay: OverlayKey,
-            val currentScene: SceneKey,
+            currentScene: SceneKey,
             currentOverlays: Flow<Set<OverlayKey>>,
             progress: Flow<Float>,
             isInitiatedByUserInput: Boolean,
@@ -159,9 +184,10 @@
             previewProgress: Flow<Float>,
             isInPreviewStage: Flow<Boolean>,
         ) :
-            Transition(
+            OverlayTransition(
                 fromOverlay,
                 toOverlay,
+                currentScene,
                 currentOverlays,
                 progress,
                 isInitiatedByUserInput,
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 dbff8a4..2e8fc14 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
@@ -176,6 +176,35 @@
         animationScope: CoroutineScope,
         transitionKey: TransitionKey? = null,
     )
+
+    /**
+     * Instantly start a [transition], running it in [animationScope].
+     *
+     * This call returns immediately and [transition] will be the [currentTransition] of this
+     * [MutableSceneTransitionLayoutState].
+     *
+     * @see startTransition
+     */
+    fun startTransitionImmediately(
+        animationScope: CoroutineScope,
+        transition: TransitionState.Transition,
+        chain: Boolean = true,
+    ): Job
+
+    /**
+     * Start a new [transition].
+     *
+     * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
+     * will run in parallel to the current transitions. If [chain] is `false`, then the list of
+     * [currentTransitions] will be cleared and [transition] will be the only running transition.
+     *
+     * If any transition is currently ongoing, it will be interrupted and forced to animate to its
+     * current state by calling [TransitionState.Transition.freezeAndAnimateToCurrentState].
+     *
+     * This method returns when [transition] is done running, i.e. when the call to
+     * [run][TransitionState.Transition.run] returns.
+     */
+    suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean = true)
 }
 
 /**
@@ -313,18 +342,10 @@
         )
     }
 
-    /**
-     * Instantly start a [transition], running it in [animationScope].
-     *
-     * This call returns immediately and [transition] will be the [currentTransition] of this
-     * [MutableSceneTransitionLayoutState].
-     *
-     * @see startTransition
-     */
-    internal fun startTransitionImmediately(
+    override fun startTransitionImmediately(
         animationScope: CoroutineScope,
         transition: TransitionState.Transition,
-        chain: Boolean = true,
+        chain: Boolean,
     ): Job {
         // Note that we start with UNDISPATCHED so that startTransition() is called directly and
         // transition becomes the current [transitionState] right after this call.
@@ -333,23 +354,7 @@
         }
     }
 
-    /**
-     * Start a new [transition].
-     *
-     * If [chain] is `true`, then the transitions will simply be added to [currentTransitions] and
-     * will run in parallel to the current transitions. If [chain] is `false`, then the list of
-     * [currentTransitions] will be cleared and [transition] will be the only running transition.
-     *
-     * If any transition is currently ongoing, it will be interrupted and forced to animate to its
-     * current state.
-     *
-     * This method returns when [transition] is done running, i.e. when the call to
-     * [run][TransitionState.Transition.run] returns.
-     */
-    internal suspend fun startTransition(
-        transition: TransitionState.Transition,
-        chain: Boolean = true,
-    ) {
+    override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) {
         checkThread()
 
         try {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index 364c203..d6751ae 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -300,7 +300,7 @@
         }
 
         /** Run this transition and return once it is finished. */
-        internal abstract suspend fun run()
+        abstract suspend fun run()
 
         /**
          * Freeze this transition state so that neither [currentScene] nor [currentOverlays] will
@@ -311,7 +311,7 @@
          *
          * This is called when this transition is interrupted (replaced) by another transition.
          */
-        internal abstract fun freezeAndAnimateToCurrentState()
+        abstract fun freezeAndAnimateToCurrentState()
 
         internal fun updateOverscrollSpecs(
             fromSpec: OverscrollSpecImpl?,
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 20a1e3c..1eed54e 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
@@ -52,6 +52,7 @@
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.assertPositionInRootIsEqualTo
 import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.hasParent
 import androidx.compose.ui.test.hasTestTag
 import androidx.compose.ui.test.hasText
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -2488,4 +2489,95 @@
         rule.waitForIdle()
         return layoutImpl
     }
+
+    @Test
+    fun elementComposableShouldPropagateMinConstraints() {
+        val contentTestTag = "content"
+        val movable = MovableElementKey("movable", contents = setOf(SceneA))
+        rule.setContent {
+            TestContentScope(currentScene = SceneA) {
+                Column {
+                    Element(TestElements.Foo, Modifier.size(40.dp)) {
+                        content {
+                            // Modifier.size() sets a preferred size and this should be ignored
+                            // because of the previously set 40dp size.
+                            Box(Modifier.testTag(contentTestTag).size(20.dp))
+                        }
+                    }
+
+                    MovableElement(movable, Modifier.size(40.dp)) {
+                        content { Box(Modifier.testTag(contentTestTag).size(20.dp)) }
+                    }
+                }
+            }
+        }
+
+        rule
+            .onNode(hasTestTag(contentTestTag) and hasParent(isElement(TestElements.Foo)))
+            .assertSizeIsEqualTo(40.dp)
+        rule
+            .onNode(hasTestTag(contentTestTag) and hasParent(isElement(movable)))
+            .assertSizeIsEqualTo(40.dp)
+    }
+
+    @Test
+    fun placeAllCopies() {
+        val foo = ElementKey("Foo", placeAllCopies = true)
+
+        @Composable
+        fun SceneScope.Foo(size: Dp, modifier: Modifier = Modifier) {
+            Box(modifier.element(foo).size(size))
+        }
+
+        rule.testTransition(
+            fromSceneContent = { Box(Modifier.size(100.dp)) { Foo(size = 10.dp) } },
+            toSceneContent = {
+                Box(Modifier.size(100.dp)) {
+                    Foo(size = 50.dp, Modifier.align(Alignment.BottomEnd))
+                }
+            },
+            transition = { spec = tween(4 * 16, easing = LinearEasing) },
+        ) {
+            before {
+                onElement(foo, SceneA)
+                    .assertSizeIsEqualTo(10.dp)
+                    .assertPositionInRootIsEqualTo(0.dp, 0.dp)
+                onElement(foo, SceneB).assertDoesNotExist()
+            }
+
+            at(16) {
+                onElement(foo, SceneA)
+                    .assertSizeIsEqualTo(20.dp)
+                    .assertPositionInRootIsEqualTo(12.5.dp, 12.5.dp)
+                onElement(foo, SceneB)
+                    .assertSizeIsEqualTo(20.dp)
+                    .assertPositionInRootIsEqualTo(12.5.dp, 12.5.dp)
+            }
+
+            at(32) {
+                onElement(foo, SceneA)
+                    .assertSizeIsEqualTo(30.dp)
+                    .assertPositionInRootIsEqualTo(25.dp, 25.dp)
+                onElement(foo, SceneB)
+                    .assertSizeIsEqualTo(30.dp)
+                    .assertPositionInRootIsEqualTo(25.dp, 25.dp)
+            }
+
+            at(48) {
+                onElement(foo, SceneA)
+                    .assertSizeIsEqualTo(40.dp)
+                    .assertPositionInRootIsEqualTo(37.5.dp, 37.5.dp)
+                onElement(foo, SceneB)
+                    .assertSizeIsEqualTo(40.dp)
+                    .assertPositionInRootIsEqualTo(37.5.dp, 37.5.dp)
+            }
+
+            after {
+                onElement(foo, SceneA).assertDoesNotExist()
+                onElement(foo, SceneB)
+                    .assertSizeIsEqualTo(50.dp)
+                    .assertPositionInRootIsEqualTo(50.dp, 50.dp)
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
index 7c9e9ce..e57702c 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -309,8 +309,10 @@
             TestContentScope {
                 Element(TestElements.Foo, Modifier.size(200.dp)) {
                     content {
-                        Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
-                        Box(Modifier.testTag("matchParentSize").matchParentSize())
+                        Box {
+                            Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
+                            Box(Modifier.testTag("matchParentSize").matchParentSize())
+                        }
                     }
                 }
             }
@@ -327,8 +329,10 @@
             TestContentScope(currentScene = SceneA) {
                 MovableElement(key, Modifier.size(200.dp)) {
                     content {
-                        Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
-                        Box(Modifier.testTag("matchParentSize").matchParentSize())
+                        Box {
+                            Box(Modifier.testTag("bottomEnd").align(Alignment.BottomEnd))
+                            Box(Modifier.testTag("matchParentSize").matchParentSize())
+                        }
                     }
                 }
             }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
index de55e2f..ea6f208 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
@@ -31,16 +31,23 @@
 import com.android.compose.animation.scene.TransitionRecordingSpec
 import com.android.compose.animation.scene.featureOfElement
 import com.android.compose.animation.scene.recordTransition
+import org.junit.ClassRule
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import platform.test.motion.compose.ComposeFeatureCaptures
 import platform.test.motion.compose.createComposeMotionTestRule
 import platform.test.motion.testing.createGoldenPathManager
+import platform.test.screenshot.ResetDeviceEmulationRule
 
 @RunWith(AndroidJUnit4::class)
 @MotionTest
 class AnchoredSizeTest {
+
+    companion object {
+        @JvmField @ClassRule val cleanupRule: ResetDeviceEmulationRule = ResetDeviceEmulationRule()
+    }
+
     private val goldenPaths =
         createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index 062d351..a1d944b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -34,9 +34,11 @@
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.testKosmos
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.mockito.mock
@@ -86,6 +88,7 @@
     @Mock private lateinit var postureController: DevicePostureController
     @Mock private lateinit var mUserActivityNotifier: UserActivityNotifier
     @Captor private lateinit var keyListenerArgumentCaptor: ArgumentCaptor<View.OnKeyListener>
+    private val kosmos = testKosmos()
 
     private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
 
@@ -132,8 +135,8 @@
                 fakeFeatureFlags,
                 mSelectedUserInteractor,
                 keyguardKeyboardInteractor,
-                null,
-                mUserActivityNotifier
+                kosmos.bouncerHapticPlayer,
+                mUserActivityNotifier,
             )
     }
 
@@ -194,7 +197,7 @@
             keyListenerArgumentCaptor.value.onKey(
                 keyguardPasswordView,
                 KeyEvent.KEYCODE_SPACE,
-                KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE)
+                KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE),
             )
 
         assertFalse("Unlock attempted.", eventHandled)
@@ -213,7 +216,7 @@
             keyListenerArgumentCaptor.value.onKey(
                 keyguardPasswordView,
                 KeyEvent.KEYCODE_ENTER,
-                KeyEvent(KeyEvent.ACTION_UP, 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/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index bb15208..d63e728 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -30,7 +30,7 @@
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
-import com.android.systemui.haptics.msdl.msdlPlayer
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
@@ -92,7 +92,7 @@
     @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
 
     private val kosmos = testKosmos()
-    private val msdlPlayer = kosmos.msdlPlayer
+    private val bouncerHapticHelper = kosmos.bouncerHapticPlayer
 
     @Before
     fun setup() {
@@ -118,7 +118,7 @@
                 mPostureController,
                 fakeFeatureFlags,
                 mSelectedUserInteractor,
-                msdlPlayer,
+                bouncerHapticHelper,
             )
         mKeyguardPatternView.onAttachedToWindow()
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 1076d90..4d1660e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -34,10 +34,12 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.res.R;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
@@ -93,6 +95,9 @@
 
     private KeyguardPinBasedInputViewController mKeyguardPinViewController;
 
+    private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this);
+    private BouncerHapticPlayer mBouncerHapticPlayer = mKosmosJavaAdapter.getBouncerHapticHelper();
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -119,7 +124,8 @@
                 mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
                 mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener,
                 mEmergencyButtonController, mFalsingCollector, featureFlags,
-                mSelectedUserInteractor, keyguardKeyboardInteractor, null, mUserActivityNotifier) {
+                mSelectedUserInteractor, keyguardKeyboardInteractor, mBouncerHapticPlayer,
+                mUserActivityNotifier) {
             @Override
             public void onResume(int reason) {
                 super.onResume(reason);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
index 43db5a7..ab59051 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
@@ -50,6 +50,9 @@
 import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.FakeLogBuffer;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository;
@@ -66,8 +69,10 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Executor;
@@ -107,6 +112,8 @@
     DreamOverlayStateController mDreamOverlayStateController;
     @Mock
     UserTracker mUserTracker;
+    @Mock
+    PrivacyItemController mPrivacyItemController;
 
     LogBuffer mLogBuffer = FakeLogBuffer.Factory.Companion.create();
 
@@ -146,6 +153,7 @@
                 mDreamOverlayStateController,
                 mUserTracker,
                 mKosmos.getWifiInteractor(),
+                mPrivacyItemController,
                 mKosmos.getCommunalSceneInteractor(),
                 mLogBuffer);
         mController.onInit();
@@ -160,6 +168,7 @@
         verify(mDreamOverlayNotificationCountProvider).addCallback(any());
         verify(mDreamOverlayStatusBarItemsProvider).addCallback(any());
         verify(mDreamOverlayStateController).addCallback(any());
+        verify(mPrivacyItemController).addCallback(any());
     }
 
     @Test
@@ -172,6 +181,52 @@
     }
 
     @Test
+    public void testLocationIconShownWhenLocationActive() {
+        mController.onViewAttached();
+        final ArgumentCaptor<PrivacyItemController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(PrivacyItemController.Callback.class);
+        verify(mPrivacyItemController).addCallback(callbackCaptor.capture());
+
+        final PrivacyItem item = Mockito.mock(PrivacyItem.class);
+        when(item.getPrivacyType()).thenReturn(PrivacyType.TYPE_LOCATION);
+        callbackCaptor.getValue().onPrivacyItemsChanged(Arrays.asList(item));
+
+        verify(mView).showIcon(
+                eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+    }
+
+    @Test
+    public void testLocationIconNotShownForOtherPrivacyItems() {
+        mController.onViewAttached();
+        final ArgumentCaptor<PrivacyItemController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(PrivacyItemController.Callback.class);
+        verify(mPrivacyItemController).addCallback(callbackCaptor.capture());
+
+        final PrivacyItem item = Mockito.mock(PrivacyItem.class);
+        when(item.getPrivacyType()).thenReturn(PrivacyType.TYPE_CAMERA);
+        callbackCaptor.getValue().onPrivacyItemsChanged(Arrays.asList(item));
+
+        verify(mView, never()).showIcon(
+                eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+    }
+
+    @Test
+    public void testLocationIconNotShownForNoItems() {
+        mController.onViewAttached();
+        final ArgumentCaptor<PrivacyItemController.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(PrivacyItemController.Callback.class);
+        verify(mPrivacyItemController).addCallback(callbackCaptor.capture());
+
+        verify(mView, never()).showIcon(
+                eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+
+        callbackCaptor.getValue().onPrivacyItemsChanged(Arrays.asList());
+
+        verify(mView, never()).showIcon(
+                eq(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE), eq(true), any());
+    }
+
+    @Test
     public void testWifiIconHiddenWhenWifiAvailable() {
         mController.onViewAttached();
         mController.updateWifiUnavailableStatusIcon(true);
@@ -274,6 +329,7 @@
                 mDreamOverlayStateController,
                 mUserTracker,
                 mKosmos.getWifiInteractor(),
+                mPrivacyItemController,
                 mKosmos.getCommunalSceneInteractor(),
                 mLogBuffer);
         controller.onViewAttached();
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 8d82e97..2ee4aee 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
@@ -16,6 +16,8 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.view.KeyEvent.KEYCODE_0
 import android.view.KeyEvent.KEYCODE_4
 import android.view.KeyEvent.KEYCODE_A
@@ -31,6 +33,7 @@
 import com.android.systemui.authentication.domain.interactor.authenticationInteractor
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 import com.android.systemui.bouncer.data.repository.fakeSimBouncerRepository
+import com.android.systemui.classifier.fakeFalsingCollector
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.lifecycle.activateIn
@@ -41,6 +44,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.random.Random
 import kotlin.random.nextInt
+import kotlin.test.assertTrue
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.map
@@ -60,12 +64,13 @@
     private val testScope = kosmos.testScope
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
     private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
-    private val underTest =
+    private val underTest by lazy {
         kosmos.pinBouncerViewModelFactory.create(
             isInputEnabled = MutableStateFlow(true),
             onIntentionalUserInput = {},
             authenticationMethod = AuthenticationMethodModel.Pin,
         )
+    }
 
     @Before
     fun setUp() {
@@ -475,6 +480,18 @@
             assertThat(pin).containsExactly(*expectedPin)
         }
 
+    @Test
+    @EnableFlags(com.android.systemui.Flags.FLAG_COMPOSE_BOUNCER)
+    @DisableFlags(com.android.systemui.Flags.FLAG_SCENE_CONTAINER)
+    fun onDigitButtonDown_avoidGesture_invoked() =
+        testScope.runTest {
+            lockDeviceAndOpenPinBouncer()
+
+            underTest.onDigitButtonDown()
+
+            assertTrue(kosmos.fakeFalsingCollector.wasLastGestureAvoided())
+        }
+
     private fun TestScope.switchToScene(toScene: SceneKey) {
         val currentScene by collectLastValue(sceneInteractor.currentScene)
         val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
index b3a12a6..1e79112 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
-import com.android.systemui.communal.widgets.CommunalAppWidgetHostView
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
@@ -61,29 +60,11 @@
                 context = context,
                 backgroundScope = kosmos.applicationCoroutineScope,
                 hostId = 116,
-                interactionHandler = mock(),
-                looper = testableLooper.looper,
                 logBuffer = logcatLogBuffer("CommunalAppWidgetHostTest"),
             )
     }
 
     @Test
-    fun createViewForCommunal_returnCommunalAppWidgetView() {
-        val appWidgetId = 789
-        val view =
-            underTest.createViewForCommunal(
-                context = context,
-                appWidgetId = appWidgetId,
-                appWidget = null
-            )
-        testableLooper.processAllMessages()
-
-        assertThat(view).isInstanceOf(CommunalAppWidgetHostView::class.java)
-        assertThat(view).isNotNull()
-        assertThat(view.appWidgetId).isEqualTo(appWidgetId)
-    }
-
-    @Test
     fun appWidgetIdToRemove_emit() =
         testScope.runTest {
             val appWidgetIdToRemove by collectLastValue(underTest.appWidgetIdToRemove)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/OverlayWindowTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/OverlayWindowTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/demomode/DemoModeControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/FaceWakeUpTriggersConfigTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt
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 3253edf..d90d58b 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
@@ -19,6 +19,7 @@
 import android.testing.TestableLooper
 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.authentication.data.repository.FakeAuthenticationRepository
@@ -42,11 +43,16 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.startable.sceneContainerStartable
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.statusbar.sysuiStatusBarStateController
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -66,10 +72,14 @@
     private val trustRepository by lazy { kosmos.fakeTrustRepository }
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
     private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
+    private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
+    private val sceneContainerStartable by lazy { kosmos.sceneContainerStartable }
+    private val sysuiStatusBarStateController by lazy { kosmos.sysuiStatusBarStateController }
     private lateinit var underTest: DeviceEntryInteractor
 
     @Before
     fun setUp() {
+        sceneContainerStartable.start()
         underTest = kosmos.deviceEntryInteractor
     }
 
@@ -423,8 +433,37 @@
             assertThat(isUnlocked).isTrue()
         }
 
-    private fun switchToScene(sceneKey: SceneKey) {
+    @Test
+    fun isDeviceEntered_unlockedWhileOnShade_emitsTrue() =
+        testScope.runTest {
+            val isDeviceEntered by collectLastValue(underTest.isDeviceEntered)
+            assertThat(isDeviceEntered).isFalse()
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+            // Navigate to shade and bouncer:
+            switchToScene(Scenes.Shade)
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            // Simulating a "leave it open when the keyguard is hidden" which means the bouncer will
+            // be
+            // shown and successful authentication should take the user back to where they are, the
+            // shade scene.
+            sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
+            switchToScene(Scenes.Bouncer)
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
+
+            assertThat(isDeviceEntered).isFalse()
+            // Authenticate with PIN to unlock and dismiss the lockscreen:
+            authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+            runCurrent()
+
+            assertThat(isDeviceEntered).isTrue()
+        }
+
+    private fun TestScope.switchToScene(sceneKey: SceneKey) {
         sceneInteractor.changeScene(sceneKey, "reason")
+        sceneInteractor.setTransitionState(flowOf(ObservableTransitionState.Idle(sceneKey)))
+        runCurrent()
     }
 
     private suspend fun givenCanShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/shared/FaceAuthReasonTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/devicepolicy/DevicePolicyManagerExtTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DeviceStateRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationUtil.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeConfigurationUtil.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeDockHandlerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeDockHandlerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeServiceFake.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeServiceFake.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuppressorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuppressorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeUiTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeUiTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/dump/LogEulogizerTest.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
index 25c5336..64915fb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
@@ -261,12 +261,12 @@
                 .registerKeyGestureEventListener(any(), listenerCaptor.capture())
 
             val allAppsKeyGestureEvent =
-                KeyGestureEvent(
-                    /* deviceId= */ 1,
-                    IntArray(0),
-                    KeyEvent.META_META_ON,
-                    KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS
-                )
+                KeyGestureEvent.Builder()
+                    .setDeviceId(1)
+                    .setModifierState(KeyEvent.META_META_ON)
+                    .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+                    .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+                    .build()
             listenerCaptor.value.onKeyGestureEvent(allAppsKeyGestureEvent)
 
             val model by
diff --git a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/emergency/EmergencyActivityTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/emergency/EmergencyActivityTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ConditionalRestarterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicDebugTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FeatureFlagsClassicReleaseTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagCommandTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagCommandTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagDependenciesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FlagDependenciesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagDependenciesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/FlagManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/NotOccludedConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/PluggedInConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/PluggedInConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/PluggedInConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/RestartDozeListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ScreenIdleConditionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/fragments/FragmentServiceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/fragments/FragmentServiceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/GlobalActionsLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ShutdownUiTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/ShutdownUiTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/data/repository/GlobalActionsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/globalactions/domain/interactor/GlobalActionsInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/slider/FakeSliderEventProducer.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartableTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/AppCategoriesShortcutsSourceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/CurrentAppShortcutsSourceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/InputShortcutsSourceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardIndicationTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ScreenLifecycleTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WakefulnessLifecycleTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfigTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyEventRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/SwipeToDismissInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/InWindowLauncherUnlockAnimationManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindParamsApplierTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListenerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSectionTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
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 e4098ae..2fd94e2 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
@@ -507,6 +507,46 @@
 
     @Test
     @DisableSceneContainer
+    fun alphaFromShadeExpansion_doesNotEmitWhenOccludedTransitionRunning() =
+        testScope.runTest {
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.LOCKSCREEN,
+                testScope,
+            )
+
+            val alpha by collectLastValue(underTest.alpha(viewState))
+            shadeTestUtil.setQsExpansion(0f)
+            runCurrent()
+            assertThat(alpha).isEqualTo(1f)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    TransitionStep(
+                        from = KeyguardState.LOCKSCREEN,
+                        to = KeyguardState.OCCLUDED,
+                        transitionState = TransitionState.STARTED,
+                        value = 0f,
+                    ),
+                    TransitionStep(
+                        from = KeyguardState.LOCKSCREEN,
+                        to = KeyguardState.OCCLUDED,
+                        transitionState = TransitionState.RUNNING,
+                        value = 0.8f,
+                    ),
+                ),
+                testScope,
+            )
+            // Alpha should be 0f from the above transition
+            assertThat(alpha).isEqualTo(0f)
+
+            shadeTestUtil.setQsExpansion(0.5f)
+            // Alpha should remain unchanged
+            assertThat(alpha).isEqualTo(0f)
+        }
+
+    @Test
+    @DisableSceneContainer
     fun alphaFromShadeExpansion_doesNotEmitWhenLockscreenToDreamTransitionRunning() =
         testScope.runTest {
             keyguardTransitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/ActivityManagerWrapperMock.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/IndicationHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/util/KeyguardTransitionRunner.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/lifecycle/ActivatableTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/ActivatableTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/lifecycle/SysUiViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/SessionTrackerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/SessionTrackerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/SessionTrackerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/core/LoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/core/LoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/core/LoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/core/LoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoSettingsFormatTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/echo/LogcatEchoTrackerDebugTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/FakeLogProxy.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/FakeLogProxy.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/TableChangeTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/log/table/TableChangeTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestUtils.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/MediaTestUtils.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/shared/SmartspaceMediaDataTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaCarouselScrollHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/view/MediaViewHolderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/util/MediaDataUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaComplicationViewControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ActivityTaskManagerThumbnailLoaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/BasicPackageManagerAppIconLoaderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/appselector/view/WindowMetricsProviderImplTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegateTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/motion/ComposeMotionTestRuleHelper.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
index b54fd86..75b090c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractorTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.qs.tiles.impl.reducebrightness.domain.interactor
 
-import android.platform.test.annotations.EnabledOnRavenwood
 import android.platform.test.annotations.RequiresFlagsDisabled
 import android.platform.test.annotations.RequiresFlagsEnabled
 import android.platform.test.flag.junit.CheckFlagsRule
@@ -46,7 +45,6 @@
 import org.mockito.kotlin.verify
 
 @SmallTest
-@EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ReduceBrightColorsTileUserActionInteractorTest : SysuiTestCase() {
 
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 2d42c42..a0cafcb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -161,9 +161,7 @@
             val upDestinationSceneKey =
                 (actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
             assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
-            kosmos.emulateUserDrivenTransition(
-                to = upDestinationSceneKey,
-            )
+            kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
 
             kosmos.fakeSceneDataSource.pause()
             kosmos.enterPin()
@@ -226,16 +224,14 @@
                 (actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
             assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home)
             assertThat(homeScene).isEqualTo(Scenes.Gone)
-            kosmos.emulateUserDrivenTransition(
-                to = homeScene,
-            )
+            kosmos.emulateUserDrivenTransition(to = homeScene)
         }
 
     @Test
     fun withAuthMethodNone_deviceWakeUp_skipsLockscreen() =
         testScope.runTest {
             kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = false)
-            kosmos.putDeviceToSleep(instantlyLockDevice = false)
+            kosmos.putDeviceToSleep()
             kosmos.assertCurrentScene(Scenes.Lockscreen)
 
             kosmos.wakeUpDevice()
@@ -246,7 +242,7 @@
     fun withAuthMethodSwipe_deviceWakeUp_doesNotSkipLockscreen() =
         testScope.runTest {
             kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
-            kosmos.putDeviceToSleep(instantlyLockDevice = false)
+            kosmos.putDeviceToSleep()
             kosmos.assertCurrentScene(Scenes.Lockscreen)
 
             kosmos.wakeUpDevice()
@@ -302,7 +298,7 @@
         testScope.runTest {
             kosmos.unlockDevice()
             kosmos.assertCurrentScene(Scenes.Gone)
-            kosmos.putDeviceToSleep(instantlyLockDevice = false)
+            kosmos.putDeviceToSleep()
             kosmos.assertCurrentScene(Scenes.Lockscreen)
 
             // Pretend like the timeout elapsed and now lock the device.
@@ -318,9 +314,7 @@
             val upDestinationSceneKey =
                 (actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
             assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
-            kosmos.emulateUserDrivenTransition(
-                to = upDestinationSceneKey,
-            )
+            kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
 
             kosmos.fakeSceneDataSource.pause()
             kosmos.dismissIme()
@@ -388,7 +382,7 @@
             kosmos.emulatePendingTransitionProgress(expectedVisible = true)
             kosmos.enterSimPin(
                 authMethodAfterSimUnlock = AuthenticationMethodModel.None,
-                enableLockscreen = false
+                enableLockscreen = false,
             )
 
             kosmos.assertCurrentScene(Scenes.Gone)
@@ -434,7 +428,7 @@
     /** Updates the current authentication method and related states in the data layer. */
     private fun Kosmos.setAuthMethod(
         authMethod: AuthenticationMethodModel,
-        enableLockscreen: Boolean = true
+        enableLockscreen: Boolean = true,
     ) {
         if (authMethod.isSecure) {
             assert(enableLockscreen) {
@@ -538,24 +532,27 @@
         kosmos.fakeSceneDataSource.pause()
         sceneInteractor.changeScene(to, "reason")
 
-        emulatePendingTransitionProgress(
-            expectedVisible = to != Scenes.Gone,
-        )
+        emulatePendingTransitionProgress(expectedVisible = to != Scenes.Gone)
     }
 
     /**
-     * Locks the device immediately (without delay).
+     * Locks the device.
      *
      * Asserts the device to be lockable (e.g. that the current authentication is secure).
      *
-     * Not to be confused with [putDeviceToSleep], which may also instantly lock the device.
+     * Internally emulates a power button press that puts the device to sleep, followed by another
+     * power button press that wakes up the device but is then expected to be in the locked state.
      */
     private suspend fun Kosmos.lockDevice() {
         val authMethod = authenticationInteractor.getAuthenticationMethod()
         assertWithMessage("The authentication method of $authMethod is not secure, cannot lock!")
             .that(authMethod.isSecure)
             .isTrue()
-        sceneInteractor.changeScene(Scenes.Lockscreen, "")
+
+        powerInteractor.setAsleepForTest()
+        testScope.runCurrent()
+
+        powerInteractor.setAwakeForTest()
         testScope.runCurrent()
     }
 
@@ -569,9 +566,7 @@
         fakeSceneDataSource.pause()
         enterPin()
 
-        emulatePendingTransitionProgress(
-            expectedVisible = false,
-        )
+        emulatePendingTransitionProgress(expectedVisible = false)
     }
 
     /**
@@ -645,9 +640,7 @@
     }
 
     /** Changes device wakefulness state from awake to asleep, going through intermediary states. */
-    private suspend fun Kosmos.putDeviceToSleep(
-        instantlyLockDevice: Boolean = true,
-    ) {
+    private suspend fun Kosmos.putDeviceToSleep() {
         val wakefulnessModel = powerInteractor.detailedWakefulness.value
         assertWithMessage("Cannot put device to sleep as it's already asleep!")
             .that(wakefulnessModel.isAwake())
@@ -655,10 +648,6 @@
 
         powerInteractor.setAsleepForTest()
         testScope.runCurrent()
-
-        if (instantlyLockDevice) {
-            lockDevice()
-        }
     }
 
     /** Emulates the dismissal of the IME (soft keyboard). */
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
index 1f3454d..405cfd3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorTest.kt
@@ -28,6 +28,8 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.sceneStackOf
 import com.android.systemui.scene.domain.startable.sceneContainerStartable
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
@@ -173,12 +175,32 @@
             )
         }
 
+    @Test
+    @EnableSceneContainer
+    fun updateBackStack() =
+        testScope.runTest {
+            underTest.onSceneChange(from = Scenes.Lockscreen, to = Scenes.Shade)
+            underTest.onSceneChange(from = Scenes.Shade, to = Scenes.QuickSettings)
+            underTest.onSceneChange(from = Scenes.QuickSettings, to = Scenes.Bouncer)
+            assertThat(underTest.backStack.value.asIterable().toList())
+                .isEqualTo(listOf(Scenes.QuickSettings, Scenes.Shade, Scenes.Lockscreen))
+
+            underTest.updateBackStack { stack ->
+                // Reverse the stack, just to see if it can be done:
+                sceneStackOf(*stack.asIterable().reversed().toTypedArray())
+            }
+
+            assertThat(underTest.backStack.value.asIterable().toList())
+                .isEqualTo(listOf(Scenes.Lockscreen, Scenes.Shade, Scenes.QuickSettings))
+        }
+
     private suspend fun TestScope.assertRoute(vararg route: RouteNode) {
         val currentScene by collectLastValue(sceneInteractor.currentScene)
         val backScene by collectLastValue(underTest.backScene)
 
         route.forEachIndexed { index, node ->
             sceneInteractor.changeScene(node.changeSceneTo, "")
+            runCurrent()
             assertWithMessage("node at index $index currentScene mismatch")
                 .that(currentScene)
                 .isEqualTo(node.changeSceneTo)
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 d180460..763a1a9 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
@@ -33,7 +33,9 @@
 import com.android.keyguard.AuthInteractionProperties
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
 import com.android.systemui.biometrics.shared.model.FingerprintSensorType
@@ -82,7 +84,9 @@
 import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakefulnessState
+import com.android.systemui.scene.data.model.asIterable
 import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
@@ -131,6 +135,7 @@
     private val testScope = kosmos.testScope
     private val deviceEntryHapticsInteractor by lazy { kosmos.deviceEntryHapticsInteractor }
     private val sceneInteractor by lazy { kosmos.sceneInteractor }
+    private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor }
     private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
     private val faceAuthRepository by lazy { kosmos.fakeDeviceEntryFaceAuthRepository }
     private val bouncerRepository by lazy { kosmos.fakeKeyguardBouncerRepository }
@@ -237,17 +242,14 @@
     fun hydrateVisibility_basedOnOcclusion() =
         testScope.runTest {
             val isVisible by collectLastValue(sceneInteractor.isVisible)
-            prepareState(
-                isDeviceUnlocked = true,
-                initialSceneKey = Scenes.Lockscreen,
-            )
+            prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Lockscreen)
 
             underTest.start()
             assertThat(isVisible).isTrue()
 
             kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
                 true,
-                mock()
+                mock(),
             )
             assertThat(isVisible).isFalse()
 
@@ -259,10 +261,7 @@
     fun hydrateVisibility_basedOnAlternateBouncer() =
         testScope.runTest {
             val isVisible by collectLastValue(sceneInteractor.isVisible)
-            prepareState(
-                isDeviceUnlocked = false,
-                initialSceneKey = Scenes.Lockscreen,
-            )
+            prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Lockscreen)
 
             underTest.start()
             assertThat(isVisible).isTrue()
@@ -270,7 +269,7 @@
             // WHEN the device is occluded,
             kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
                 true,
-                mock()
+                mock(),
             )
             // THEN scenes are not visible
             assertThat(isVisible).isFalse()
@@ -393,6 +392,7 @@
     fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked_whenLeaveOpenShade() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+            val backStack by collectLastValue(sceneBackInteractor.backStack)
             kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open
 
             val transitionState =
@@ -414,12 +414,14 @@
             transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer)
             runCurrent()
             assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
+            assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Lockscreen)
 
             kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
                 SuccessFingerprintAuthenticationStatus(0, true)
             )
 
             assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings)
+            assertThat(backStack?.asIterable()?.last()).isEqualTo(Scenes.Gone)
         }
 
     @Test
@@ -478,10 +480,7 @@
     fun stayOnLockscreenWhenDeviceUnlocksWithBypassOff() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
-            prepareState(
-                isBypassEnabled = false,
-                initialSceneKey = Scenes.Lockscreen,
-            )
+            prepareState(isBypassEnabled = false, initialSceneKey = Scenes.Lockscreen)
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
 
@@ -520,10 +519,7 @@
     fun switchToGoneWhenDeviceIsUnlockedAndUserIsOnBouncerWithBypassDisabled() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
-            prepareState(
-                isBypassEnabled = false,
-                initialSceneKey = Scenes.Bouncer,
-            )
+            prepareState(isBypassEnabled = false, initialSceneKey = Scenes.Bouncer)
             assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer)
             underTest.start()
 
@@ -539,10 +535,7 @@
             val alternateBouncerVisible by
                 collectLastValue(bouncerRepository.alternateBouncerVisible)
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
-            prepareState(
-                isDeviceUnlocked = false,
-                initialSceneKey = Scenes.Shade,
-            )
+            prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
             assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
             bouncerRepository.setAlternateVisible(true)
             underTest.start()
@@ -564,10 +557,7 @@
     fun switchToLockscreenWhenDeviceSleepsLocked() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
-            prepareState(
-                isDeviceUnlocked = false,
-                initialSceneKey = Scenes.Shade,
-            )
+            prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
             assertThat(currentSceneKey).isEqualTo(Scenes.Shade)
             underTest.start()
             powerInteractor.setAsleepForTest()
@@ -583,10 +573,7 @@
             val currentTransitionInfo by
                 collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
             val transitionState =
-                prepareState(
-                    isDeviceUnlocked = false,
-                    initialSceneKey = Scenes.Shade,
-                )
+                prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
             kosmos.keyguardRepository.setAodAvailable(true)
             runCurrent()
             assertThat(asleepState).isEqualTo(KeyguardState.AOD)
@@ -615,10 +602,7 @@
             val currentTransitionInfo by
                 collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal)
             val transitionState =
-                prepareState(
-                    isDeviceUnlocked = false,
-                    initialSceneKey = Scenes.Shade,
-                )
+                prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Shade)
             kosmos.keyguardRepository.setAodAvailable(false)
             runCurrent()
             assertThat(asleepState).isEqualTo(KeyguardState.DOZING)
@@ -1078,16 +1062,14 @@
     @Test
     fun hydrateSystemUiState_onLockscreen_basedOnOcclusion() =
         testScope.runTest {
-            prepareState(
-                initialSceneKey = Scenes.Lockscreen,
-            )
+            prepareState(initialSceneKey = Scenes.Lockscreen)
             underTest.start()
             runCurrent()
             clearInvocations(sysUiState)
 
             kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
                 true,
-                mock()
+                mock(),
             )
             runCurrent()
             assertThat(
@@ -1210,7 +1192,7 @@
                 initialSceneKey = Scenes.Lockscreen,
                 authenticationMethod = AuthenticationMethodModel.Pin,
                 isDeviceUnlocked = false,
-                startsAwake = false
+                startsAwake = false,
             )
             assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
             underTest.start()
@@ -1228,11 +1210,14 @@
     @Test
     fun collectFalsingSignals_onSuccessfulUnlock() =
         testScope.runTest {
-            prepareState(
-                initialSceneKey = Scenes.Lockscreen,
-                authenticationMethod = AuthenticationMethodModel.Pin,
-                isDeviceUnlocked = false,
-            )
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+
+            val transitionStateFlow =
+                prepareState(
+                    initialSceneKey = Scenes.Lockscreen,
+                    authenticationMethod = AuthenticationMethodModel.Pin,
+                    isDeviceUnlocked = false,
+                )
             underTest.start()
             runCurrent()
             verify(falsingCollector, never()).onSuccessfulUnlock()
@@ -1247,36 +1232,46 @@
                 )
                 .forEach { sceneKey ->
                     sceneInteractor.changeScene(sceneKey, "reason")
+                    transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
                     runCurrent()
                     verify(falsingCollector, never()).onSuccessfulUnlock()
                 }
 
             // Changing to the Gone scene should report a successful unlock.
-            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
-                SuccessFingerprintAuthenticationStatus(0, true)
-            )
+            kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
             runCurrent()
-            sceneInteractor.changeScene(Scenes.Gone, "reason")
+            // Make sure that the startable changed the scene to Gone because the device unlocked.
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+            // Make the transition state match the current state
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             runCurrent()
             verify(falsingCollector).onSuccessfulUnlock()
 
             // Move around scenes without changing back to Lockscreen, shouldn't report another
             // unlock.
-            listOf(
-                    Scenes.Shade,
-                    Scenes.QuickSettings,
-                    Scenes.Shade,
-                    Scenes.Gone,
-                )
-                .forEach { sceneKey ->
-                    sceneInteractor.changeScene(sceneKey, "reason")
-                    runCurrent()
-                    verify(falsingCollector, times(1)).onSuccessfulUnlock()
-                }
+            listOf(Scenes.Shade, Scenes.QuickSettings, Scenes.Shade, Scenes.Gone).forEach { sceneKey
+                ->
+                sceneInteractor.changeScene(sceneKey, "reason")
+                transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
+                runCurrent()
+                verify(falsingCollector, times(1)).onSuccessfulUnlock()
+            }
 
-            // Changing to the Lockscreen scene shouldn't report a successful unlock.
-            sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+            // Putting the device to sleep to lock it again, which shouldn't report another
+            // successful unlock.
+            kosmos.powerInteractor.setAsleepForTest()
             runCurrent()
+            // Verify that the startable changed the scene to Lockscreen because the device locked
+            // following the sleep.
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            // Make the transition state match the current state
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+            // Wake up the device again before continuing with the test.
+            kosmos.powerInteractor.setAwakeForTest()
+            runCurrent()
+            // Verify that the current scene is still the Lockscreen scene, now that the device is
+            // still locked.
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
             verify(falsingCollector, times(1)).onSuccessfulUnlock()
 
             // Move around scenes without unlocking.
@@ -1289,12 +1284,17 @@
                 )
                 .forEach { sceneKey ->
                     sceneInteractor.changeScene(sceneKey, "reason")
+                    transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
                     runCurrent()
                     verify(falsingCollector, times(1)).onSuccessfulUnlock()
                 }
 
-            // Changing to the Gone scene should report a second successful unlock.
-            sceneInteractor.changeScene(Scenes.Gone, "reason")
+            kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+            runCurrent()
+            // Make sure that the startable changed the scene to Gone because the device unlocked.
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+            // Make the transition state match the current scene.
+            transitionStateFlow.value = ObservableTransitionState.Idle(Scenes.Gone)
             runCurrent()
             verify(falsingCollector, times(2)).onSuccessfulUnlock()
         }
@@ -1608,7 +1608,7 @@
 
             kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
                 true,
-                mock()
+                mock(),
             )
             runCurrent()
             verify(notificationShadeWindowController, times(1)).setKeyguardOccluded(true)
@@ -1623,10 +1623,7 @@
     @Test
     fun hydrateInteractionState_whileLocked() =
         testScope.runTest {
-            val transitionStateFlow =
-                prepareState(
-                    initialSceneKey = Scenes.Lockscreen,
-                )
+            val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen)
             underTest.start()
             runCurrent()
             verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
@@ -1643,10 +1640,7 @@
                 },
                 verifyAfterTransition = {
                     verify(centralSurfaces)
-                        .setInteracting(
-                            StatusBarManager.WINDOW_STATUS_BAR,
-                            false,
-                        )
+                        .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false)
                 },
             )
 
@@ -1661,11 +1655,7 @@
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
                 verifyAfterTransition = {
-                    verify(centralSurfaces)
-                        .setInteracting(
-                            StatusBarManager.WINDOW_STATUS_BAR,
-                            true,
-                        )
+                    verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
                 },
             )
 
@@ -1681,10 +1671,7 @@
                 },
                 verifyAfterTransition = {
                     verify(centralSurfaces)
-                        .setInteracting(
-                            StatusBarManager.WINDOW_STATUS_BAR,
-                            false,
-                        )
+                        .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false)
                 },
             )
 
@@ -1699,11 +1686,7 @@
                     verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
                 },
                 verifyAfterTransition = {
-                    verify(centralSurfaces)
-                        .setInteracting(
-                            StatusBarManager.WINDOW_STATUS_BAR,
-                            true,
-                        )
+                    verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
                 },
             )
 
@@ -1881,9 +1864,7 @@
         testScope.runTest {
             val currentScene by collectLastValue(sceneInteractor.currentScene)
             val transitionStateFlow =
-                prepareState(
-                    authenticationMethod = AuthenticationMethodModel.None,
-                )
+                prepareState(authenticationMethod = AuthenticationMethodModel.None)
             underTest.start()
             assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
             // Swipe to Gone, more than halfway
@@ -1949,9 +1930,7 @@
     fun switchToGone_whenKeyguardBecomesDisabled_whenOnShadeScene() =
         testScope.runTest {
             val currentScene by collectLastValue(sceneInteractor.currentScene)
-            prepareState(
-                initialSceneKey = Scenes.Shade,
-            )
+            prepareState(initialSceneKey = Scenes.Shade)
             assertThat(currentScene).isEqualTo(Scenes.Shade)
             underTest.start()
 
@@ -1981,10 +1960,7 @@
     fun doesNotSwitchToGone_whenKeyguardBecomesDisabled_whenDeviceEntered() =
         testScope.runTest {
             val currentScene by collectLastValue(sceneInteractor.currentScene)
-            prepareState(
-                isDeviceUnlocked = true,
-                initialSceneKey = Scenes.Gone,
-            )
+            prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Gone)
             assertThat(currentScene).isEqualTo(Scenes.Gone)
             assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isTrue()
             underTest.start()
@@ -2097,10 +2073,7 @@
     fun refreshLockscreenEnabled() =
         testScope.runTest {
             val transitionState =
-                prepareState(
-                    isDeviceUnlocked = true,
-                    initialSceneKey = Scenes.Gone,
-                )
+                prepareState(isDeviceUnlocked = true, initialSceneKey = Scenes.Gone)
             underTest.start()
             val isLockscreenEnabled by
                 collectLastValue(kosmos.deviceEntryInteractor.isLockscreenEnabled)
@@ -2174,10 +2147,7 @@
         runCurrent()
         verifyDuringTransition?.invoke()
 
-        transitionStateFlow.value =
-            ObservableTransitionState.Idle(
-                currentScene = toScene,
-            )
+        transitionStateFlow.value = ObservableTransitionState.Idle(currentScene = toScene)
         runCurrent()
         verifyAfterTransition?.invoke()
     }
@@ -2262,7 +2232,7 @@
 
     private fun TestScope.allowHapticsOnSfps(
         isPowerButtonDown: Boolean = false,
-        lastPowerPress: Long = 10000
+        lastPowerPress: Long = 10000,
     ) {
         kosmos.fakeKeyEventRepository.setPowerButtonDown(isPowerButtonDown)
 
@@ -2287,7 +2257,7 @@
     private fun TestScope.setupBiometricAuth(
         hasSfps: Boolean = false,
         hasUdfps: Boolean = false,
-        hasFace: Boolean = false
+        hasFace: Boolean = false,
     ) {
         if (hasSfps) {
             setFingerprintSensorType(FingerprintSensorType.POWER_BUTTON)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt
index 2a2817b..ad2b23e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt
@@ -88,6 +88,26 @@
         }
 
     @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun isDualShade_flagEnabled_true() =
+        testScope.runTest {
+            // Initiate collection.
+            val shadeMode by collectLastValue(underTest.shadeMode)
+
+            assertThat(underTest.isDualShade).isTrue()
+        }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun isDualShade_flagDisabled_false() =
+        testScope.runTest {
+            // Initiate collection.
+            val shadeMode by collectLastValue(underTest.shadeMode)
+
+            assertThat(underTest.isDualShade).isFalse()
+        }
+
+    @Test
     fun getTopEdgeSplitFraction_narrowScreen_splitInHalf() =
         testScope.runTest {
             // Ensure isShadeLayoutWide is collected.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
index 469a7bc..3053672 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.kt
@@ -38,7 +38,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 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.notification.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.DelayableExecutor
diff --git a/packages/SystemUI/res/drawable/ic_volume_media_off.xml b/packages/SystemUI/res/drawable/ic_volume_media_off.xml
deleted file mode 100644
index 875b7b6..0000000
--- a/packages/SystemUI/res/drawable/ic_volume_media_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_volume_media_mute" />
-</selector>
diff --git a/packages/SystemUI/res/layout/ambient_status_bar_view.xml b/packages/SystemUI/res/layout/ambient_status_bar_view.xml
index 7d765ce..825824a 100644
--- a/packages/SystemUI/res/layout/ambient_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/ambient_status_bar_view.xml
@@ -53,6 +53,15 @@
         app:layout_constraintEnd_toEndOf="parent">
 
         <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:id="@+id/dream_overlay_location_active"
+            android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
+            android:layout_height="match_parent"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
+            android:src="@drawable/ic_location"
+            android:visibility="gone"
+            android:contentDescription="@string/location_active_dream_overlay_content_description" />
+
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
             android:id="@+id/dream_overlay_alarm_set"
             android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/raw/trackpad_recent_apps_edu.json b/packages/SystemUI/res/raw/trackpad_recent_apps_edu.json
new file mode 100644
index 0000000..c2e945d
--- /dev/null
+++ b/packages/SystemUI/res/raw/trackpad_recent_apps_edu.json
@@ -0,0 +1 @@
+{"v":"5.12.1","fr":60,"ip":0,"op":511,"w":554,"h":564,"nm":"Trackpad-JSON_Recents-EDU","ddd":0,"assets":[{"id":"comp_0","nm":"Recents_EDU Loop","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"CNTL || playback","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"s":true,"x":{"a":0,"k":0},"y":{"a":0,"k":0}},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Picker","np":3,"mn":"Pseudo/@@WcSiov6sT3a4/s0XPKYEOQ","ix":1,"en":1,"ef":[{"ty":7,"nm":"Menu","mn":"Pseudo/@@WcSiov6sT3a4/s0XPKYEOQ-0001","ix":1,"v":{"a":0,"k":2}}]},{"ty":5,"nm":"OUTPUT","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"k":[{"s":[0],"t":142,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.001],"t":143,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.002],"t":144,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.003],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.004],"t":146,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.006],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.008],"t":148,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.01],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.012],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.016],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.02],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.025],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.031],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.038],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.047],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.059],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.073],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.091],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.116],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.15],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.196],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.249],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.306],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.366],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.425],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.481],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.53],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.575],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.614],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.648],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.678],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.706],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.73],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.752],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.772],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.79],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.807],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.822],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.836],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.849],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.861],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.873],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.883],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.892],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.901],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.91],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.917],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.925],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.931],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.937],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.943],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.949],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.954],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.958],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.963],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.967],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.97],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.974],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.977],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.98],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.983],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.985],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.987],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.989],"t":205,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.991],"t":206,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.993],"t":207,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.994],"t":208,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.996],"t":209,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.997],"t":210,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.998],"t":211,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.998],"t":212,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.999],"t":213,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1],"t":215,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1],"t":250,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.009],"t":251,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.038],"t":252,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.093],"t":253,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.193],"t":254,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.4],"t":255,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.636],"t":256,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.739],"t":257,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.8],"t":258,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.84],"t":259,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.871],"t":260,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.894],"t":261,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.912],"t":262,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.928],"t":263,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.94],"t":264,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.951],"t":265,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.959],"t":266,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.967],"t":267,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.973],"t":268,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.979],"t":269,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.983],"t":270,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.987],"t":271,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.99],"t":272,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.993],"t":273,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.995],"t":274,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.997],"t":275,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.998],"t":276,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.999],"t":278,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2],"t":380,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.009],"t":381,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.038],"t":382,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.093],"t":383,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.193],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.4],"t":385,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.636],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.739],"t":387,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.8],"t":388,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.84],"t":389,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.871],"t":390,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.894],"t":391,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.912],"t":392,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.928],"t":393,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.94],"t":394,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.951],"t":395,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.959],"t":396,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.967],"t":397,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.973],"t":398,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.979],"t":399,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.983],"t":400,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.987],"t":401,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.99],"t":402,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.993],"t":403,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.995],"t":404,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.997],"t":405,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[2.999],"t":408,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]}}]},{"ty":5,"nm":"Keys","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.831],"y":[0.109]},"o":{"x":[0.458],"y":[0.053]},"t":142,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.15],"y":[0.43]},"t":161,"s":[0.15]},{"t":217,"s":[1],"h":1},{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":250,"s":[1]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":255,"s":[1.4]},{"t":280,"s":[2],"h":1},{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":380,"s":[2]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":385,"s":[2.4]},{"t":410,"s":[3]}]}}]},{"ty":5,"nm":"State (holds)","np":3,"mn":"ADBE Slider Control","ix":4,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":0}}]}],"shapes":[],"ip":0,"op":451,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null :: Taskbar drop","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"k":[{"s":[252,278,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,278.45,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,279.615,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,281.252,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,283.166,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,287.233,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,289.181,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,290.982,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,292.599,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,294.012,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,295.216,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,296.216,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,297.023,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,297.655,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.131,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.474,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.705,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.465,0],"t":212,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.226,0],"t":215,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298,0],"t":377,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,298.382,0],"t":378,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,299.372,0],"t":379,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,300.764,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,302.391,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,305.848,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,307.504,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,309.035,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,310.409,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,311.611,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,312.634,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,313.483,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,314.169,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,314.706,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.112,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.403,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.717,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.474,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,315.192,0],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Taskbar Lofi","parent":3,"refId":"comp_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":134,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":143,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":432,"s":[100]},{"t":444,"s":[0]}]},"r":{"a":0,"k":0},"p":{"s":true,"x":{"a":0,"k":0},"y":{"k":[{"s":[26.984],"t":127,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.971],"t":128,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.95],"t":129,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.921],"t":130,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.882],"t":131,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.83],"t":132,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.765],"t":133,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.685],"t":134,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.589],"t":135,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.478],"t":136,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.349],"t":137,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.205],"t":138,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.072],"t":139,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.926],"t":140,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.764],"t":141,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.589],"t":142,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.397],"t":143,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.187],"t":144,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.959],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.711],"t":146,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.44],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.146],"t":148,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.826],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.479],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.1],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.686],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.236],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[21.745],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[21.207],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[20.616],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.967],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.248],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.457],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.578],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.602],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.514],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.303],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[12.954],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[11.477],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[9.885],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[8.215],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[6.526],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[4.878],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[3.338],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.928],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.659],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.475],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-1.485],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-2.388],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-3.192],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-3.911],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-4.556],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-5.136],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-5.662],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.135],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.563],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.951],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-7.303],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-7.622],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-7.913],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.175],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.413],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.628],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.823],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.998],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.155],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.296],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.42],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.531],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.627],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.711],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.783],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.843],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.893],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.933],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.963],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.984],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-9.996],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]}},"a":{"a":0,"k":[91,15,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":138,"s":[17.5]},{"t":205,"s":[100]}]}}]}],"w":182,"h":30,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":3,"nm":"Focus Task :: Lift & Drop","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"s":true,"x":{"a":0,"k":252},"y":{"k":[{"s":[157.385],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.28],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.128],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.026],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.901],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.75],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.564],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.335],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.054],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.706],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.275],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[154.73],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[154.03],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[153.103],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[151.8],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[150.035],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[148.047],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.867],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[143.589],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[141.341],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[139.241],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[137.346],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[135.666],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[134.185],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[132.878],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[131.718],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[130.684],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[129.755],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[128.916],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[128.155],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[127.462],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[126.829],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[126.249],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[125.715],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[125.221],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[124.765],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[124.343],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[123.951],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[123.587],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[123.249],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.934],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.641],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.369],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.114],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.877],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.657],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.452],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.26],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[121.082],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.918],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.764],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.623],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.492],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.371],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.261],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.158],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.065],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.98],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.903],"t":205,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.835],"t":206,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.718],"t":208,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.629],"t":210,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.51],"t":215,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.5],"t":250,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[119.746],"t":251,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[120.54],"t":252,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[122.071],"t":253,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[124.808],"t":254,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[130.5],"t":255,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[136.982],"t":256,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[139.835],"t":257,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[141.489],"t":258,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[142.613],"t":259,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[143.442],"t":260,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[144.082],"t":261,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[144.593],"t":262,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.01],"t":263,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.354],"t":264,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.642],"t":265,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[145.884],"t":266,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.089],"t":267,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.262],"t":268,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.409],"t":269,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.534],"t":270,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.638],"t":271,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.725],"t":272,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[146.857],"t":274,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147],"t":380,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147.094],"t":381,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147.397],"t":382,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[147.982],"t":383,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[149.027],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[151.2],"t":385,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[153.675],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[154.764],"t":387,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.396],"t":388,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[155.825],"t":389,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.141],"t":390,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.386],"t":391,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.581],"t":392,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.74],"t":393,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.871],"t":394,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[156.981],"t":395,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.074],"t":396,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.218],"t":398,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[157.362],"t":401,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]}},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"matte","parent":5,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"k":[{"s":[503.613,314.758],"t":144,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.134,314.459],"t":146,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.832,314.27],"t":147,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.464,314.04],"t":148,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.025,313.765],"t":149,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[501.487,313.429],"t":150,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[500.824,313.015],"t":151,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[500.023,312.514],"t":152,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[499.032,311.895],"t":153,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[497.818,311.136],"t":154,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[496.328,310.205],"t":155,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[494.484,309.053],"t":156,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[492.194,307.621],"t":157,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[489.307,305.817],"t":158,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[485.592,303.495],"t":159,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[480.67,300.419],"t":160,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[473.76,296.1],"t":161,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[464.395,290.247],"t":162,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[453.849,283.656],"t":163,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[442.286,276.429],"t":164,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[430.198,268.874],"t":165,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[418.274,261.421],"t":166,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[407.131,254.457],"t":167,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[397.077,248.173],"t":168,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[388.165,242.603],"t":169,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[380.31,237.694],"t":170,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[373.373,233.358],"t":171,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[367.218,229.511],"t":172,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[361.732,226.082],"t":173,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[356.803,223.002],"t":174,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[352.354,220.221],"t":175,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[348.318,217.699],"t":176,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[344.643,215.402],"t":177,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[341.283,213.302],"t":178,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[338.205,211.378],"t":179,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[335.37,209.606],"t":180,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[332.752,207.97],"t":181,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[330.33,206.456],"t":182,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[328.092,205.058],"t":183,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[326.012,203.757],"t":184,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[324.082,202.552],"t":185,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[322.291,201.432],"t":186,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[320.617,200.386],"t":187,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[319.062,199.414],"t":188,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[317.618,198.512],"t":189,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[316.267,197.667],"t":190,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[315.013,196.883],"t":191,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[313.845,196.153],"t":192,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[312.756,195.472],"t":193,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[311.738,194.837],"t":194,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[310.793,194.246],"t":195,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[309.921,193.7],"t":196,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[309.107,193.192],"t":197,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[308.359,192.724],"t":198,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[307.663,192.289],"t":199,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[307.02,191.888],"t":200,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[306.436,191.522],"t":201,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[305.891,191.182],"t":202,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[305.399,190.874],"t":203,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[304.946,190.591],"t":204,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[304.539,190.337],"t":205,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[304.178,190.112],"t":206,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.85,189.906],"t":207,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.555,189.722],"t":208,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.306,189.566],"t":209,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[303.082,189.427],"t":210,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.892,189.308],"t":211,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.617,189.135],"t":213,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.4,189],"t":250,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[302.247,188.904],"t":251,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[301.752,188.595],"t":252,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[300.798,187.999],"t":253,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[299.093,186.933],"t":254,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[295.546,184.716],"t":255,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[291.506,182.192],"t":256,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[289.729,181.08],"t":257,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[288.698,180.436],"t":258,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.998,179.999],"t":259,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.481,179.676],"t":260,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.082,179.427],"t":261,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.764,179.227],"t":262,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.504,179.065],"t":263,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.29,178.931],"t":264,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[286.11,178.819],"t":265,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.832,178.645],"t":267,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.555,178.472],"t":270,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.272,178.295],"t":278,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[285.264,178.29],"t":380,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[287.222,179.514],"t":381,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[293.538,183.461],"t":382,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[305.714,191.071],"t":383,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[327.48,204.675],"t":384,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[372.758,232.974],"t":385,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[424.317,265.198],"t":386,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[447.009,279.381],"t":387,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[460.167,287.605],"t":388,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[469.103,293.19],"t":389,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[475.697,297.31],"t":390,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[480.788,300.492],"t":391,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[484.853,303.033],"t":392,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[488.172,305.107],"t":393,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[490.906,306.816],"t":394,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[493.198,308.249],"t":395,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[495.121,309.451],"t":396,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[496.752,310.47],"t":397,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[498.133,311.333],"t":398,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[499.301,312.063],"t":399,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[500.29,312.681],"t":400,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[501.123,313.202],"t":401,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[501.814,313.634],"t":402,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.391,313.994],"t":403,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[502.861,314.288],"t":404,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.238,314.524],"t":405,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.53,314.706],"t":406,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0]},"r":{"k":[{"s":[27.974],"t":144,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.959],"t":145,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.942],"t":146,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.922],"t":147,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.898],"t":148,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.869],"t":149,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.833],"t":150,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.789],"t":151,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.736],"t":152,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.67],"t":153,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.589],"t":154,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.49],"t":155,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.368],"t":156,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.216],"t":157,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.024],"t":158,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.777],"t":159,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.45],"t":160,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.991],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.37],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.669],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.901],"t":164,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[23.098],"t":165,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.306],"t":166,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[21.566],"t":167,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[20.898],"t":168,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[20.306],"t":169,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.785],"t":170,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.324],"t":171,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.915],"t":172,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.551],"t":173,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[18.223],"t":174,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.928],"t":175,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.66],"t":176,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.416],"t":177,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[17.193],"t":178,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.988],"t":179,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.8],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.626],"t":181,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.465],"t":182,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.316],"t":183,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.178],"t":184,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.05],"t":185,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.931],"t":186,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.82],"t":187,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.717],"t":188,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.621],"t":189,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.531],"t":190,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.448],"t":191,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.37],"t":192,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.298],"t":193,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.23],"t":194,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.167],"t":195,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.11],"t":196,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.055],"t":197,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.006],"t":198,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.96],"t":199,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.917],"t":200,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.878],"t":201,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.842],"t":202,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.809],"t":203,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.779],"t":204,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.752],"t":205,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.728],"t":206,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.706],"t":207,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.687],"t":208,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.67],"t":209,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.655],"t":210,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.643],"t":211,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.633],"t":212,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.624],"t":213,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.61],"t":250,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.603],"t":251,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.579],"t":252,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.532],"t":253,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.45],"t":254,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.278],"t":255,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.082],"t":256,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.996],"t":257,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.946],"t":258,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.912],"t":259,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.887],"t":260,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.868],"t":261,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.853],"t":262,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.84],"t":263,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.83],"t":264,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.821],"t":265,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.808],"t":267,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.794],"t":270,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.78],"t":278,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.78],"t":380,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[13.907],"t":381,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[14.318],"t":382,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[15.109],"t":383,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[16.524],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[19.468],"t":385,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[22.82],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[24.295],"t":387,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.15],"t":388,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[25.731],"t":389,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.16],"t":390,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.491],"t":391,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.755],"t":392,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[26.971],"t":393,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.149],"t":394,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.298],"t":395,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.423],"t":396,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.529],"t":397,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.619],"t":398,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.694],"t":399,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.759],"t":400,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.813],"t":401,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.858],"t":402,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.895],"t":403,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.926],"t":404,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.95],"t":405,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.969],"t":406,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[27.993],"t":408,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Recents_LofiApp","parent":6,"tt":1,"tp":6,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[252,157.5,0]},"s":{"k":[{"s":[99.923,99.923,100],"t":144,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.828,99.828,100],"t":146,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.768,99.768,100],"t":147,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.695,99.695,100],"t":148,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.608,99.608,100],"t":149,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.501,99.501,100],"t":150,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.37,99.37,100],"t":151,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.211,99.211,100],"t":152,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.014,99.014,100],"t":153,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.773,98.773,100],"t":154,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.478,98.478,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.112,98.112,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.658,97.658,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.085,97.085,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.348,96.348,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.371,95.371,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94,94,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.142,92.142,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.049,90.049,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[87.755,87.755,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.357,85.357,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[82.991,82.991,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.78,80.78,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[78.785,78.785,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[77.017,77.017,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[75.458,75.458,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[74.082,74.082,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[72.861,72.861,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[71.772,71.772,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70.794,70.794,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[69.911,69.911,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[69.111,69.111,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.382,68.382,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[67.715,67.715,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[67.104,67.104,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[66.542,66.542,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[66.022,66.022,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[65.542,65.542,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[65.098,65.098,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[64.685,64.685,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[64.302,64.302,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.947,63.947,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.615,63.615,100],"t":187,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.306,63.306,100],"t":188,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.02,63.02,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.751,62.751,100],"t":190,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.503,62.503,100],"t":191,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.271,62.271,100],"t":192,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[62.055,62.055,100],"t":193,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.853,61.853,100],"t":194,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.665,61.665,100],"t":195,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.492,61.492,100],"t":196,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.331,61.331,100],"t":197,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.182,61.182,100],"t":198,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[61.044,61.044,100],"t":199,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.917,60.917,100],"t":200,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.801,60.801,100],"t":201,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.693,60.693,100],"t":202,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.595,60.595,100],"t":203,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.505,60.505,100],"t":204,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.424,60.424,100],"t":205,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.353,60.353,100],"t":206,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.288,60.288,100],"t":207,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.229,60.229,100],"t":208,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.18,60.18,100],"t":209,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.135,60.135,100],"t":210,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.098,60.098,100],"t":211,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.043,60.043,100],"t":213,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60,60,100],"t":250,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.97,59.97,100],"t":251,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.871,59.871,100],"t":252,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.682,59.682,100],"t":253,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[59.344,59.344,100],"t":254,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[58.64,58.64,100],"t":255,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.839,57.839,100],"t":256,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.486,57.486,100],"t":257,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.281,57.281,100],"t":258,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.142,57.142,100],"t":259,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.04,57.04,100],"t":260,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.961,56.961,100],"t":261,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.898,56.898,100],"t":262,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.846,56.846,100],"t":263,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.804,56.804,100],"t":264,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.768,56.768,100],"t":265,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.713,56.713,100],"t":267,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.658,56.658,100],"t":270,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.602,56.602,100],"t":278,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.6,56.6,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.989,56.989,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[58.242,58.242,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.657,60.657,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[64.976,64.976,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[73.96,73.96,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[84.19,84.19,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.692,88.692,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[91.303,91.303,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.076,93.076,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.384,94.384,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.394,95.394,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.201,96.201,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.859,96.859,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.402,97.402,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.857,97.857,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.238,98.238,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.562,98.562,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.836,98.836,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.068,99.068,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.264,99.264,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.429,99.429,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.566,99.566,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.681,99.681,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.774,99.774,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.849,99.849,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.907,99.907,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"w":504,"h":315,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":7,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[0]},{"t":277,"s":[100]}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,-30.035,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[176.678,176.678,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"second Tasks Zoom back","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.8,0.8,0.8],"y":[0.15,0.15,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":380,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.05,0.05,0.05],"y":[0.7,0.7,0]},"t":385,"s":[98,98,100]},{"t":410,"s":[95,95,100]}]}},"ao":0,"shapes":[],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Null :: Reposition Side Task","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.8,"y":0.15},"o":{"x":0.3,"y":0},"t":250,"s":[-318.4,-38,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.05,"y":0.7},"t":255,"s":[-277.34,-48.1,0],"to":[0,0,0],"ti":[0,0,0]},{"t":280,"s":[-215.75,-63.25,0]}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":277,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[0,-111.72,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-111.197,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-109.514,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-106.268,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-100.462,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-88.39,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-74.643,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-68.591,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-65.083,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-62.7,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-60.943,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-59.584,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-58.5,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-57.616,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-56.886,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-56.276,0],"t":265,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-55.762,0],"t":266,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-55.328,0],"t":267,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.96,0],"t":268,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.648,0],"t":269,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.385,0],"t":270,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-54.163,0],"t":271,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.977,0],"t":272,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.824,0],"t":273,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.698,0],"t":274,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.598,0],"t":275,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.521,0],"t":276,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.463,0],"t":277,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.424,0],"t":278,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":10,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.05,"y":0.963},"t":217,"s":[-84.8,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":250,"s":[0,0,0]}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.8,0.8],"y":[0.15,0.15]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":250,"s":[302.4,189]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0.7]},"t":255,"s":[227.56,142.34]},{"t":280,"s":[115.3,72.35]}]},"p":{"a":0,"k":[0,0]},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":250,"s":[14.6]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":255,"s":[14.272]},{"t":280,"s":[13.78]}]},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":14,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":268,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":277,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[0,-53.175,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-53.175,0],"t":510,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":9,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":383,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.8,"y":0.15},"o":{"x":0.3,"y":0},"t":250,"s":[-411.95,20.325,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.05,"y":0.7},"t":255,"s":[-333.47,29.183,0],"to":[0,0,0],"ti":[0,0,0]},{"t":280,"s":[-215.75,42.47,0]}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[115.3,72.35]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":13.78},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":197,"op":511,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Taskbar Lofi","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"app - 5","parent":9,"sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[51.5,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.652,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.136,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.013,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.449,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.806,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.3,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[66.437,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[68.94,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[70.432,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[71.462,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[72.229,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[72.83,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[73.314,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[73.714,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.048,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.334,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.578,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.789,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[74.971,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.131,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.269,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.389,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.493,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.584,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.663,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.731,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.789,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.839,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.915,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.982,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[76,0,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.779,0,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[75.066,0,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[73.709,0,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[71.271,0,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[66.2,0,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[60.425,0,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.886,0,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.41,0,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.409,0,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.67,0,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.1,0,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.646,0,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.275,0,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.968,0,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.711,0,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.495,0,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.312,0,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.157,0,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.026,0,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.916,0,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.822,0,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.745,0,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.68,0,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.628,0,0],"t":404,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.585,0,0],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.552,0,0],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.501,0,0],"t":409,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[167,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7511","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[167,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 5","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"app - 4","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[123.341,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.654,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.223,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[125.146,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[126.662,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[129.549,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[132.838,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[134.455,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[135.421,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[136.083,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[136.576,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[136.962,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.272,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.528,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.742,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.924,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.08,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.216,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.334,15,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.437,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.527,15,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.606,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.734,15,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.869,15,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.864,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[138.402,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[137.527,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[135.96,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[132.701,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[129.002,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[127.358,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[126.406,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[125.763,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[125.288,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.923,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.633,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.396,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.199,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[124.034,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.895,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.776,15,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.675,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.589,15,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.516,15,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.403,15,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.299,15,0],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[139,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7508","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[139,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 4","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"app - 3","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[104.041,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.182,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.436,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.844,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.517,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[106.808,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[108.265,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[108.981,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.409,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.703,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.923,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.092,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.228,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.341,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.436,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.517,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.587,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.648,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.746,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.853,15,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.956,15,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.938,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.73,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.34,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[109.649,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[108.197,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[106.559,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.828,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.403,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[105.117,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.906,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.745,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.616,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.511,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.424,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.35,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.288,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.19,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[104.091,15,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[111,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7507","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[111,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 3","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"app - 2","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[84.704,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.639,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.537,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.371,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.048,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.684,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.505,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.398,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.324,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.271,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.195,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.123,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.045,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.068,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.166,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.338,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.702,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.112,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.294,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.399,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.47,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.521,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.593,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[84.676,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[83,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7506","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[83,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 2","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"app - 1","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[65.439,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.229,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.849,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.236,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.226,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.296,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.111,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[58.033,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.388,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.945,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.616,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.359,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.154,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.984,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.842,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.72,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.616,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.525,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.447,15,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.378,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.317,15,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.265,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.219,15,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.178,15,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.143,15,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.113,15,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.066,15,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.012,15,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55,15,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.092,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.403,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.986,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.027,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[59.212,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[61.67,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[62.762,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.396,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[63.825,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.141,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.385,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.578,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.736,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.867,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[64.977,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.07,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.149,15,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.217,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.274,15,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.323,15,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.364,15,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.426,15,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[65.491,15,0],"t":407,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[55,15,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 7505","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[55,15]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app - 1","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"divider","sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":90},"p":{"k":[{"s":[51,15,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.913,15,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.615,15,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.073,15,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.194,15,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.751,15,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.001,15,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.869,15,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[40.328,15,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.409,15,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.778,15,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.309,15,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.941,15,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.645,15,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.402,15,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.199,15,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.025,15,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.876,15,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.747,15,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.635,15,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.536,15,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.451,15,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.376,15,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.31,15,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.253,15,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.203,15,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.161,15,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.124,15,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.093,15,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.068,15,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.047,15,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.017,15,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36,15,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.129,15,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.569,15,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[37.403,15,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[38.895,15,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.999,15,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.522,15,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.088,15,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.994,15,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[48.607,15,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.059,15,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.407,15,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.683,15,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.909,15,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.096,15,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.253,15,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.386,15,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.499,15,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.596,15,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.677,15,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.747,15,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.806,15,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.854,15,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.895,15,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.927,15,0],"t":404,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.973,15,0],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2,-0.5],[2,-0.5]],"c":false}],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.019,-0.5],[2.019,-0.5]],"c":false}],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.077,-0.5],[2.077,-0.5]],"c":false}],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.185,-0.5],[2.185,-0.5]],"c":false}],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.361,-0.5],[2.361,-0.5]],"c":false}],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.65,-0.5],[2.65,-0.5]],"c":false}],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.2,-0.5],[3.2,-0.5]],"c":false}],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.829,-0.5],[3.829,-0.5]],"c":false}],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.136,-0.5],[4.136,-0.5]],"c":false}],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.318,-0.5],[4.318,-0.5]],"c":false}],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.444,-0.5],[4.444,-0.5]],"c":false}],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.538,-0.5],[4.538,-0.5]],"c":false}],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.612,-0.5],[4.612,-0.5]],"c":false}],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.671,-0.5],[4.671,-0.5]],"c":false}],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.72,-0.5],[4.72,-0.5]],"c":false}],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.761,-0.5],[4.761,-0.5]],"c":false}],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.796,-0.5],[4.796,-0.5]],"c":false}],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.826,-0.5],[4.826,-0.5]],"c":false}],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.852,-0.5],[4.852,-0.5]],"c":false}],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.874,-0.5],[4.874,-0.5]],"c":false}],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.894,-0.5],[4.894,-0.5]],"c":false}],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.91,-0.5],[4.91,-0.5]],"c":false}],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.925,-0.5],[4.925,-0.5]],"c":false}],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.938,-0.5],[4.938,-0.5]],"c":false}],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.949,-0.5],[4.949,-0.5]],"c":false}],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.959,-0.5],[4.959,-0.5]],"c":false}],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.967,-0.5],[4.967,-0.5]],"c":false}],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.974,-0.5],[4.974,-0.5]],"c":false}],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.98,-0.5],[4.98,-0.5]],"c":false}],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.99,-0.5],[4.99,-0.5]],"c":false}],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.996,-0.5],[4.996,-0.5]],"c":false}],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,-0.5],[5,-0.5]],"c":false}],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.973,-0.5],[4.973,-0.5]],"c":false}],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.887,-0.5],[4.887,-0.5]],"c":false}],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.72,-0.5],[4.72,-0.5]],"c":false}],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-4.421,-0.5],[4.421,-0.5]],"c":false}],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.8,-0.5],[3.8,-0.5]],"c":false}],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.093,-0.5],[3.093,-0.5]],"c":false}],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.782,-0.5],[2.782,-0.5]],"c":false}],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.601,-0.5],[2.601,-0.5]],"c":false}],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.479,-0.5],[2.479,-0.5]],"c":false}],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.388,-0.5],[2.388,-0.5]],"c":false}],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.318,-0.5],[2.318,-0.5]],"c":false}],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.263,-0.5],[2.263,-0.5]],"c":false}],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.217,-0.5],[2.217,-0.5]],"c":false}],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.18,-0.5],[2.18,-0.5]],"c":false}],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.148,-0.5],[2.148,-0.5]],"c":false}],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.122,-0.5],[2.122,-0.5]],"c":false}],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.099,-0.5],[2.099,-0.5]],"c":false}],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.081,-0.5],[2.081,-0.5]],"c":false}],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.064,-0.5],[2.064,-0.5]],"c":false}],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.051,-0.5],[2.051,-0.5]],"c":false}],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.039,-0.5],[2.039,-0.5]],"c":false}],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.03,-0.5],[2.03,-0.5]],"c":false}],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.022,-0.5],[2.022,-0.5]],"c":false}],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.01,-0.5],[2.01,-0.5]],"c":false}],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.006,-0.5],[2.006,-0.5]],"c":false}],"t":406,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.004,-0.5],[2.004,-0.5]],"c":false}],"t":407,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.001,-0.5],[2.001,-0.5]],"c":false}],"t":408,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"nm":"Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"divider","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":9,"sr":1,"ks":{"o":{"k":[{"s":[0],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[54.85],"t":162,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":163,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":384,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":386,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[-52.349,0.652,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.453,0.652,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.813,0.652,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.464,0.652,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.515,0.652,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.247,0.652,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-59.565,0.652,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-63.323,0.652,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-65.162,0.652,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-66.258,0.652,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-67.015,0.652,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-67.578,0.652,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.019,0.652,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.375,0.652,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.668,0.652,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.914,0.652,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.122,0.652,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.301,0.652,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.456,0.652,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.59,0.652,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.708,0.652,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.81,0.652,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.9,0.652,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.978,0.652,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.047,0.652,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.106,0.652,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.157,0.652,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.2,0.652,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.268,0.652,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.328,0.652,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.349,0.652,0],"t":380,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-70.193,0.652,0],"t":381,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.662,0.652,0],"t":382,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.662,0.652,0],"t":383,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-66.874,0.652,0],"t":384,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-63.132,0.652,0],"t":385,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.906,0.652,0],"t":386,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.04,0.652,0],"t":387,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.956,0.652,0],"t":388,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.22,0.652,0],"t":389,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.678,0.652,0],"t":390,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.259,0.652,0],"t":391,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.925,0.652,0],"t":392,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.654,0.652,0],"t":393,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.43,0.652,0],"t":394,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.241,0.652,0],"t":395,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.082,0.652,0],"t":396,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.947,0.652,0],"t":397,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.831,0.652,0],"t":398,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.734,0.652,0],"t":399,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.65,0.652,0],"t":400,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.58,0.652,0],"t":401,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.522,0.652,0],"t":402,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.474,0.652,0],"t":403,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.435,0.652,0],"t":404,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.404,0.652,0],"t":405,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.354,0.652,0],"t":408,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[6.826,6.826,0]},"s":{"k":[{"s":[50,50,100],"t":155,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.309,50.309,100],"t":156,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.284,51.284,100],"t":157,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.079,53.079,100],"t":158,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.019,56.019,100],"t":159,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.828,60.828,100],"t":160,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[70,70,100],"t":161,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80.485,80.485,100],"t":162,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[85.597,85.597,100],"t":163,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[88.641,88.641,100],"t":164,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.739,90.739,100],"t":165,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[92.305,92.305,100],"t":166,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.53,93.53,100],"t":167,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.518,94.518,100],"t":168,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.335,95.335,100],"t":169,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.021,96.021,100],"t":170,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.603,96.603,100],"t":171,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.101,97.101,100],"t":172,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.531,97.531,100],"t":173,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.902,97.902,100],"t":174,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.226,98.226,100],"t":175,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.507,98.507,100],"t":176,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.753,98.753,100],"t":177,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.966,98.966,100],"t":178,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.152,99.152,100],"t":179,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.313,99.313,100],"t":180,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.451,99.451,100],"t":181,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.57,99.57,100],"t":182,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.671,99.671,100],"t":183,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.756,99.756,100],"t":184,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.826,99.826,100],"t":185,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.883,99.883,100],"t":186,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.982,99.982,100],"t":189,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[100,100,100],"t":380,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.552,99.552,100],"t":381,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.109,98.109,100],"t":382,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.326,95.326,100],"t":383,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[90.35,90.35,100],"t":384,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[80,80,100],"t":385,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[68.215,68.215,100],"t":386,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[63.027,63.027,100],"t":387,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[60.02,60.02,100],"t":388,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[57.977,57.977,100],"t":389,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[56.47,56.47,100],"t":390,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[55.306,55.306,100],"t":391,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[54.377,54.377,100],"t":392,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[53.618,53.618,100],"t":393,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.993,52.993,100],"t":394,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.469,52.469,100],"t":395,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[52.03,52.03,100],"t":396,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.657,51.657,100],"t":397,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.341,51.341,100],"t":398,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[51.074,51.074,100],"t":399,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.848,50.848,100],"t":400,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.658,50.658,100],"t":401,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.5,50.5,100],"t":402,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.368,50.368,100],"t":403,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.26,50.26,100],"t":404,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.174,50.174,100],"t":405,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.107,50.107,100],"t":406,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.059,50.059,100],"t":407,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[50.024,50.024,100],"t":408,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 12","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[2.5,9.501]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 12","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 11","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[2.5,2.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 11","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true}},"nm":"Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 5","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[9.5,2.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Ellipse 5","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true}},"nm":"Path 1","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 1","hd":false},{"ind":2,"ty":"sh","ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true}},"nm":"Path 2","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 2","hd":false},{"ty":"st","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.4},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"icon","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[10.326,10.326]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"icon","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[91,15,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[{"s":[120,4],"t":155,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.383,4.161],"t":156,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.592,4.668],"t":157,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[123.818,5.601],"t":158,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[127.463,7.13],"t":159,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[133.427,9.631],"t":160,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[144.8,14.4],"t":161,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[157.801,19.852],"t":162,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[164.141,22.511],"t":163,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[167.915,24.093],"t":164,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[170.516,25.184],"t":165,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[172.458,25.999],"t":166,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[173.978,26.636],"t":167,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[175.203,27.15],"t":168,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[176.216,27.574],"t":169,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[177.065,27.931],"t":170,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[177.788,28.234],"t":171,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[178.406,28.493],"t":172,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[178.938,28.716],"t":173,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[179.399,28.909],"t":174,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[179.8,29.078],"t":175,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.149,29.224],"t":176,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.454,29.352],"t":177,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.718,29.463],"t":178,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[180.949,29.559],"t":179,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.148,29.643],"t":180,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.32,29.715],"t":181,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.467,29.777],"t":182,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.592,29.829],"t":183,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.697,29.873],"t":184,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.784,29.91],"t":185,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.855,29.939],"t":186,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.909,29.962],"t":187,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.978,29.991],"t":189,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[182,30],"t":380,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[181.445,29.767],"t":381,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[179.655,29.017],"t":382,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[176.204,27.569],"t":383,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[170.034,24.982],"t":384,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[157.2,19.6],"t":385,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[142.586,13.472],"t":386,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[136.154,10.774],"t":387,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[132.424,9.21],"t":388,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[129.891,8.148],"t":389,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[128.022,7.364],"t":390,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[126.579,6.759],"t":391,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[125.427,6.276],"t":392,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[124.487,5.881],"t":393,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[123.712,5.556],"t":394,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[123.062,5.284],"t":395,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[122.517,5.055],"t":396,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[122.055,4.862],"t":397,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.663,4.697],"t":398,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.332,4.559],"t":399,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[121.051,4.441],"t":400,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.815,4.342],"t":401,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.62,4.26],"t":402,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.456,4.191],"t":403,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.323,4.135],"t":404,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.216,4.091],"t":405,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.133,4.056],"t":406,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.073,4.03],"t":407,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.03,4.013],"t":408,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[120.008,4.003],"t":409,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":32.672},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Taskbar Lofi","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"Recents_LofiApp","fr":60,"pfr":1,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[339.937,151.75,0]},"a":{"a":0,"k":[339.937,151.75,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.021,-1.766],[0,0],[-2.043,0],[0,0],[1.022,1.767]],"o":[[-1.021,-1.766],[0,0],[-1.022,1.767],[0,0],[2.043,0],[0,0]],"v":[[2.297,-7.675],[-2.297,-7.675],[-9.64,5.025],[-7.343,9],[7.343,9],[9.64,5.025]],"c":true}},"nm":"Path 1","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":9},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[481.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[457.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[292,25]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[334,279]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109,28]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[425.5,208.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[160,56]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[400,158.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126,40]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[251,78.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[334,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[340,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":16},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82,171.125,0]},"a":{"a":0,"k":[82,171.125,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,177.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 4","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,165.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,171.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 2","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82.5,140.5,0]},"a":{"a":0,"k":[82,140.938,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,22]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Search","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,31.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"header","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,257.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 6","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,245.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 5","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,251.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,64]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,171]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"block","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,96.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,84.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,90.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 1","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app only","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","parent":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":250,"s":[100]},{"t":256,"s":[0]}]},"r":{"a":0,"k":0},"p":{"k":[{"s":[0,29.984,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.965,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.936,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.894,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.84,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.77,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.682,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.574,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.445,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.294,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,29.121,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.925,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.746,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.548,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.33,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,28.092,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,27.832,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,27.548,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,27.239,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,26.903,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,26.536,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,26.14,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,25.709,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,25.241,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,24.73,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,24.171,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,23.563,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,22.898,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,22.171,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,21.373,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,20.496,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,19.524,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,18.451,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,17.263,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,15.943,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,14.475,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,12.841,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,11.018,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,9.023,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,6.87,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,4.614,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,2.333,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,0.106,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-1.975,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-3.877,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-5.591,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-7.125,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-8.492,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-9.714,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-10.799,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-11.771,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-12.643,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-13.428,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-14.138,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-14.777,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-15.355,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-15.879,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-16.354,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-16.784,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-17.177,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-17.532,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-17.854,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.146,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.409,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.645,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-18.858,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.048,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.217,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.366,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.496,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.61,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.707,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.788,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.856,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.911,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.954,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,-19.984,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":138,"s":[17.5]},{"t":205,"s":[100]}]}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":248,"s":[28,28]},{"t":258,"s":[36,36]}]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[33,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":248,"s":[33,0],"to":[0,0],"ti":[0,0]},{"t":258,"s":[41,0]}]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"right circle","bm":0,"hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":248,"s":[28,28]},{"t":258,"s":[36,36]}]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[-41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[-33,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":248,"s":[-33,0],"to":[0,0],"ti":[0,0]},{"t":258,"s":[-41,0]}]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"left circle","bm":0,"hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":248,"s":[28,28]},{"t":258,"s":[36,36]}]},"p":{"a":0,"k":[0,0]},"nm":"Ellipse Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"size","bm":0,"hd":false}],"ip":37,"op":345,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,459,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":18},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Frame 1321317559","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Recents_EDU Loop","parent":4,"tt":1,"tp":4,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[252,157.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":504,"h":315,"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":50},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"illustrations: action key","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.768627464771,0.627451002598,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"illustrations: action key","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"k":[{"s":[7],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[7],"t":511,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lj":1,"ml":{"a":0,"k":4},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"frame","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}],"markers":[{"tm":121,"cm":"start","dr":0},{"tm":142,"cm":"gesture","dr":75},{"tm":250,"cm":"release","dr":36},{"tm":356,"cm":"FLIP","dr":0},{"tm":392,"cm":"launch","dr":66}],"props":{}}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/trackpad_recent_apps_success.json b/packages/SystemUI/res/raw/trackpad_recent_apps_success.json
new file mode 100644
index 0000000..bec6f35
--- /dev/null
+++ b/packages/SystemUI/res/raw/trackpad_recent_apps_success.json
@@ -0,0 +1 @@
+{"v":"5.12.1","fr":60,"ip":0,"op":50,"w":554,"h":564,"nm":"Trackpad-JSON_Recents-Success","ddd":0,"assets":[{"id":"comp_0","nm":"TrackpadAK_Success_Checkmark","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Check Rotate","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.12],"y":[1]},"o":{"x":[0.44],"y":[0]},"t":2,"s":[-16]},{"t":20,"s":[6]}]},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[95.049,95.049,100]}},"ao":0,"ip":0,"op":228,"st":-72,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Bounce","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.12],"y":[1]},"o":{"x":[0.44],"y":[0]},"t":12,"s":[0]},{"t":36,"s":[-6]}]},"p":{"a":0,"k":[81,127,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.263,0.263,0.833],"y":[1.126,1.126,1]},"o":{"x":[0.05,0.05,0.05],"y":[0.958,0.958,0]},"t":1,"s":[80,80,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.45,0.45,0.167],"y":[0.325,0.325,0]},"t":20,"s":[105,105,100]},{"t":36,"s":[100,100,100]}]}},"ao":0,"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-0.289},"p":{"a":0,"k":[14.364,-33.591,0]},"a":{"a":0,"k":[-0.125,0,0]},"s":{"a":0,"k":[104.744,104.744,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[-1.401,-0.007],[-10.033,11.235]],"o":[[5.954,7.288],[1.401,0.007],[0,0]],"v":[[-28.591,4.149],[-10.73,26.013],[31.482,-21.255]],"c":false}},"nm":"Path 1","hd":false},{"ty":"tm","s":{"a":0,"k":0},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":3,"s":[0]},{"i":{"x":[0.22],"y":[1]},"o":{"x":[0.001],"y":[0.149]},"t":10,"s":[29]},{"t":27,"s":[100]}]},"o":{"a":0,"k":0},"m":1,"nm":"Trim Paths 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":11},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Shape 1","bm":0,"hd":false}],"ip":5,"op":44,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[95,95,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.275,0.275,0.21],"y":[1.102,1.102,1]},"o":{"x":[0.037,0.037,0.05],"y":[0.476,0.476,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.252,0.252,0.47],"y":[0.159,0.159,0]},"t":16,"s":[120,120,100]},{"t":28,"s":[100,100,100]}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.32,0.32],"y":[0.11,0.11]},"t":16,"s":[148,148]},{"t":28,"s":[136,136]}]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":88},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Checkbox - Widget","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Recents_LofiApp","fr":60,"pfr":1,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[339.937,151.75,0]},"a":{"a":0,"k":[339.937,151.75,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"a":0,"k":{"i":[[0,0],[1.021,-1.766],[0,0],[-2.043,0],[0,0],[1.022,1.767]],"o":[[-1.021,-1.766],[0,0],[-1.022,1.767],[0,0],[2.043,0],[0,0]],"v":[[2.297,-7.675],[-2.297,-7.675],[-9.64,5.025],[-7.343,9],[7.343,9],[9.64,5.025]],"c":true}},"nm":"Path 1","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":9},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[481.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Triangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[457.874,21]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Rectangle","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[292,25]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[334,279]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Text field","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109,28]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[425.5,208.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[160,56]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[400,158.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Sent","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126,40]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":14},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[251,78.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Received","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[334,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[340,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":16},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82,171.125,0]},"a":{"a":0,"k":[82,171.125,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,177.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 4","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,165.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,171.125]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 2","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[82.5,140.5,0]},"a":{"a":0,"k":[82,140.938,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,22]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":39.375},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Search","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,31.5]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"header","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,257.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 6","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,245.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 5","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,251.375]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 3","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,64]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":12},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Message","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[82,171]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"block","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[80,96.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 2","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[94,84.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Line 1","bm":0,"hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":200},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Avatar","bm":0,"hd":false},{"ty":"tr","p":{"a":0,"k":[34,90.875]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"circle 1","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[252,157.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"app only","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"TrackpadAK_Success_Checkmark","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,198.5,0]},"a":{"a":0,"k":[95,95,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":190,"h":190,"ip":6,"op":50,"st":6,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onSecondaryFixed","cl":"onSecondaryFixed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":389,"s":[100]},{"t":392,"s":[0]}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Global Position","np":4,"mn":"Pseudo/88900","ix":1,"en":1,"ef":[{"ty":10,"nm":"Master Parent","mn":"Pseudo/88900-0001","ix":1,"v":{"a":0,"k":2}},{"ty":3,"nm":"Global Position","mn":"Pseudo/88900-0002","ix":2,"v":{"k":[{"s":[277,197.5],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5],"t":49,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.145098039216,0.101960784314,0.01568627451,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,459,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":18},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.32549020648,0.270588248968,0.164705887437,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"Frame 1321317559","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":511,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Recents_LofiApp","tt":1,"tp":4,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[252,157.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"w":504,"h":315,"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".onSecondaryFixedVariant","cl":"onSecondaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ef":[{"ty":5,"nm":"Global Position","np":4,"mn":"Pseudo/88900","ix":1,"en":1,"ef":[{"ty":10,"nm":"Master Parent","mn":"Pseudo/88900-0001","ix":1,"v":{"a":0,"k":2}},{"ty":3,"nm":"Global Position","mn":"Pseudo/88900-0002","ix":2,"v":{"k":[{"s":[277,197.5],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5],"t":49,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325490196078,0.270588235294,0.164705882353,1]},"o":{"a":0,"k":50},"r":1,"bm":0,"nm":"Fill 1","hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.768627464771,0.627451002598,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"illustrations: action key","bm":0,"hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".secondaryFixedDim","cl":"secondaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[277,197.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":28},"nm":"Rectangle Path 1","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":14},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"k":[{"s":[7],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[7],"t":49,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lj":1,"ml":{"a":0,"k":4},"hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980392157,0.76862745098,0.627450980392,1]},"o":{"a":0,"k":100},"r":1,"bm":0,"nm":"Fill 1","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"Transform"}],"nm":"frame","bm":0,"hd":false}],"ip":0,"op":50,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e1808fa..e94248d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1976,6 +1976,14 @@
     <dimen name="backlight_indicator_step_small_radius">4dp</dimen>
     <dimen name="backlight_indicator_step_large_radius">28dp</dimen>
 
+    <!-- Touchpad gestures tutorial-->
+    <!-- This value is in unit of dp/ms
+        TriggerSwipeUpTouchTracker (which is base for gesture tutorial implementation) uses value
+        of 0.5dp but from manual testing it's too high and doesn't really feel like it's forcing
+        slowing down. Also for tutorial it should be fine to lean to the side of being more strict
+        rather than not strict enough and not teaching user the proper gesture as a result.-->
+    <dimen name="touchpad_recent_apps_gesture_velocity_threshold">0.05dp</dimen>
+
     <!-- Broadcast dialog -->
     <dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
     <dimen name="broadcast_dialog_title_text_size">24sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 589d9dd..f9c2aef 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3369,6 +3369,8 @@
     <!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
     <string name="drag_split_not_supported">This notification does not support dragging to split screen</string>
 
+    <!-- Content description for the location icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+    <string name="dream_overlay_location_active">Location active</string>
     <!-- Content description for the Wi-Fi off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
     <string name="dream_overlay_status_bar_wifi_off">Wi\u2011Fi unavailable</string>
     <!-- Content description for the priority mode icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
@@ -3561,6 +3563,9 @@
     <!-- Content description for Wi-Fi not available icon on dream [CHAR LIMIT=NONE]-->
     <string name="wifi_unavailable_dream_overlay_content_description">Wi-Fi not available</string>
 
+    <!-- Content description for location in use icon on dream [CHAR LIMIT=NONE] -->
+    <string name="location_active_dream_overlay_content_description">Location active</string>
+
     <!-- Content description for camera blocked icon on dream [CHAR LIMIT=NONE] -->
     <string name="camera_blocked_dream_overlay_content_description">Camera blocked</string>
 
@@ -3724,8 +3729,8 @@
     <string name="touchpad_tutorial_back_gesture_button">Back gesture</string>
     <!-- Label for button opening tutorial for back gesture on touchpad [CHAR LIMIT=NONE] -->
     <string name="touchpad_tutorial_home_gesture_button">Home gesture</string>
-    <!-- Label for button opening tutorial on using Action key from keyboard [CHAR LIMIT=NONE] -->
-    <string name="touchpad_tutorial_action_key_button">Action key</string>
+    <!-- Label for button opening tutorial for "view recent apps" gesture on touchpad [CHAR LIMIT=NONE] -->
+    <string name="touchpad_tutorial_recent_apps_gesture_button">View recent apps</string>
     <!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] -->
     <string name="touchpad_tutorial_done_button">Done</string>
     <!-- BACK GESTURE -->
@@ -3747,6 +3752,15 @@
     <string name="touchpad_home_gesture_success_title">Nice!</string>
     <!-- Text shown to the user after they complete home gesture tutorial [CHAR LIMIT=NONE] -->
     <string name="touchpad_home_gesture_success_body">You completed the go home gesture.</string>
+    <!-- RECENT APPS GESTURE -->
+    <!-- Touchpad recent apps gesture action name in tutorial [CHAR LIMIT=NONE] -->
+    <string name="touchpad_recent_apps_gesture_action_title">View recent apps</string>
+    <!-- Touchpad recent apps gesture guidance in gestures tutorial [CHAR LIMIT=NONE] -->
+    <string name="touchpad_recent_apps_gesture_guidance">Swipe up and hold using three fingers on your touchpad.</string>
+    <!-- Screen title after recent apps gesture was done successfully [CHAR LIMIT=NONE] -->
+    <string name="touchpad_recent_apps_gesture_success_title">Great job!</string>
+    <!-- Text shown to the user after they complete recent apps gesture tutorial [CHAR LIMIT=NONE] -->
+    <string name="touchpad_recent_apps_gesture_success_body">You completed the view recent apps gesture.</string>
 
     <!-- KEYBOARD TUTORIAL-->
     <!-- Action key tutorial title [CHAR LIMIT=NONE] -->
@@ -3802,16 +3816,16 @@
     <string name="all_apps_edu_notification_content">Press the action key at any time. Tap to learn more gestures.</string>
 
     <!-- Title for Extra Dim dialog [CHAR LIMIT=NONE] -->
-    <string name="accessibility_deprecate_extra_dim_dialog_title">Extra dim is now part of the brightness bar</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_title">Extra dim is now part of the brightness slider</string>
     <!-- Content description for Extra Dim dialog. This helps users understand that we could make screen much dimmer by lowering the brightness through the brightness bar in a dark environment. [CHAR LIMIT=NONE] -->
     <string name="accessibility_deprecate_extra_dim_dialog_description">
-        You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment.
+        You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed.
     </string>
     <!-- Label for button removing Extra Dim shortcuts [CHAR LIMIT=NONE] -->
-    <string name="accessibility_deprecate_extra_dim_dialog_button">Remove extra dim shortcut</string>
+    <string name="accessibility_deprecate_extra_dim_dialog_button">Remove extra dim shortcuts</string>
     <!-- Toast message for notifying users to use regular brightness bar to lower the brightness. [CHAR LIMIT=NONE] -->
     <string name="accessibility_deprecate_extra_dim_dialog_toast">
-        Extra dim shortcut removed. To lower your brightness, use the regular brightness bar.</string>
+        Extra dim shortcuts removed</string>
 
     <!-- Label for category in QS Edit mode list of tiles, for tiles that are related to connectivity, e.g. Internet. [CHAR LIMIT=NONE] -->
     <string name="qs_edit_mode_category_connectivity">
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 0f1da50..8f55961 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -70,7 +70,6 @@
         "jsr330",
         "//frameworks/libs/systemui:com_android_systemui_shared_flags_lib",
         "//frameworks/libs/systemui:msdl",
-        "//frameworks/libs/systemui:view_capture",
     ],
     resource_dirs: [
         "res",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index 4db6ab6..f358ba2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.shared.rotation;
 
-import static com.android.app.viewcapture.ViewCaptureFactory.getViewCaptureAwareWindowManagerInstance;
-import static com.android.systemui.Flags.enableViewCaptureTracing;
-
 import android.annotation.DimenRes;
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
@@ -33,6 +30,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.widget.FrameLayout;
@@ -40,7 +38,6 @@
 import androidx.annotation.BoolRes;
 import androidx.core.view.OneShotPreDrawListener;
 
-import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
 import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator.Position;
 
 /**
@@ -50,7 +47,7 @@
 
     private static final int MARGIN_ANIMATION_DURATION_MILLIS = 300;
 
-    private final ViewCaptureAwareWindowManager mWindowManager;
+    private final WindowManager mWindowManager;
     private final ViewGroup mKeyButtonContainer;
     private final FloatingRotationButtonView mKeyButtonView;
 
@@ -91,8 +88,7 @@
             @DimenRes int taskbarBottomMargin, @DimenRes int buttonDiameter,
             @DimenRes int rippleMaxWidth, @BoolRes int floatingRotationBtnPositionLeftResource) {
         mContext = context;
-        mWindowManager = getViewCaptureAwareWindowManagerInstance(mContext,
-                enableViewCaptureTracing());
+        mWindowManager = mContext.getSystemService(WindowManager.class);
         mKeyButtonContainer = (ViewGroup) LayoutInflater.from(mContext).inflate(layout, null);
         mKeyButtonView = mKeyButtonContainer.findViewById(keyButtonId);
         mKeyButtonView.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 28f1381..b43d8b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -19,10 +19,8 @@
 import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
 import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
 import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
-import static com.android.systemui.Flags.msdlFeedback;
 import static com.android.systemui.Flags.notifyPasswordTextViewUserActivityInBackground;
 
-import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.os.AsyncTask;
 import android.os.CountDownTimer;
@@ -37,15 +35,13 @@
 import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback;
 import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingClassifier;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.res.R;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
-import com.google.android.msdl.data.model.MSDLToken;
-import com.google.android.msdl.domain.MSDLPlayer;
-
 import java.util.HashMap;
 import java.util.Map;
 
@@ -62,8 +58,6 @@
     protected AsyncTask<?, ?, ?> mPendingLockCheck;
     protected boolean mResumed;
     protected boolean mLockedOut;
-    @Nullable
-    protected MSDLPlayer mMSDLPlayer;
 
     private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> {
         // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
@@ -91,16 +85,16 @@
             LatencyTracker latencyTracker, FalsingCollector falsingCollector,
             EmergencyButtonController emergencyButtonController,
             FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor,
-            @Nullable MSDLPlayer msdlPlayer,
+            BouncerHapticPlayer bouncerHapticPlayer,
             UserActivityNotifier userActivityNotifier) {
         super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
-                messageAreaControllerFactory, featureFlags, selectedUserInteractor);
+                messageAreaControllerFactory, featureFlags, selectedUserInteractor,
+                bouncerHapticPlayer);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
         mFalsingCollector = falsingCollector;
         mEmergencyButtonController = emergencyButtonController;
-        mMSDLPlayer = msdlPlayer;
         mUserActivityNotifier = userActivityNotifier;
     }
 
@@ -191,7 +185,9 @@
     void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) {
         boolean dismissKeyguard = mSelectedUserInteractor.getSelectedUserId() == userId;
         if (matched) {
-            playAuthenticationHaptics(/* unlock= */true);
+            mBouncerHapticPlayer.playAuthenticationFeedback(
+                    /* authenticationSucceeded = */true
+            );
             getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
             if (dismissKeyguard) {
                 mDismissing = true;
@@ -199,7 +195,9 @@
                 getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode());
             }
         } else {
-            playAuthenticationHaptics(/* unlock= */false);
+            mBouncerHapticPlayer.playAuthenticationFeedback(
+                    /* authenticationSucceeded = */false
+            );
             mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
             if (isValidPassword) {
                 getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
@@ -216,18 +214,6 @@
         }
     }
 
-    private void playAuthenticationHaptics(boolean unlock) {
-        if (!msdlFeedback() || mMSDLPlayer == null) return;
-
-        MSDLToken token;
-        if (unlock) {
-            token = MSDLToken.UNLOCK;
-        } else {
-            token = MSDLToken.FAILURE;
-        }
-        mMSDLPlayer.playToken(token, mAuthInteractionProperties);
-    }
-
     protected void startErrorAnimation() { /* no-op */ }
 
     protected void verifyPasswordAndUnlock() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 92e5432..ff78848 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -35,6 +35,7 @@
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
 import com.android.systemui.bouncer.ui.BouncerMessageView;
 import com.android.systemui.bouncer.ui.binder.BouncerMessageViewBinder;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
@@ -45,9 +46,6 @@
 import com.android.systemui.util.ViewController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
-import com.google.android.msdl.domain.InteractionProperties;
-import com.google.android.msdl.domain.MSDLPlayer;
-
 import javax.inject.Inject;
 
 /** Controller for a {@link KeyguardSecurityView}. */
@@ -66,21 +64,22 @@
     private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {};
     private final FeatureFlags mFeatureFlags;
     protected final SelectedUserInteractor mSelectedUserInteractor;
-    protected final InteractionProperties mAuthInteractionProperties =
-            new AuthInteractionProperties();
+    protected final BouncerHapticPlayer mBouncerHapticPlayer;
 
     protected KeyguardInputViewController(T view, SecurityMode securityMode,
             KeyguardSecurityCallback keyguardSecurityCallback,
             EmergencyButtonController emergencyButtonController,
             @Nullable KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             FeatureFlags featureFlags,
-            SelectedUserInteractor selectedUserInteractor) {
+            SelectedUserInteractor selectedUserInteractor,
+            BouncerHapticPlayer bouncerHapticPlayer) {
         super(view);
         mSecurityMode = securityMode;
         mKeyguardSecurityCallback = keyguardSecurityCallback;
         mEmergencyButtonController = emergencyButtonController;
         mFeatureFlags = featureFlags;
         mSelectedUserInteractor = selectedUserInteractor;
+        mBouncerHapticPlayer = bouncerHapticPlayer;
         if (messageAreaControllerFactory != null) {
             try {
                 BouncerKeyguardMessageArea kma = view.requireViewById(R.id.bouncer_message_area);
@@ -219,7 +218,7 @@
         private final SelectedUserInteractor mSelectedUserInteractor;
         private final UiEventLogger mUiEventLogger;
         private final KeyguardKeyboardInteractor mKeyguardKeyboardInteractor;
-        private final MSDLPlayer mMSDLPlayer;
+        private final BouncerHapticPlayer mBouncerHapticPlayer;
         private final UserActivityNotifier mUserActivityNotifier;
 
         @Inject
@@ -236,7 +235,7 @@
                 FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor,
                 UiEventLogger uiEventLogger,
                 KeyguardKeyboardInteractor keyguardKeyboardInteractor,
-                MSDLPlayer msdlPlayer,
+                BouncerHapticPlayer bouncerHapticPlayer,
                 UserActivityNotifier userActivityNotifier) {
             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
             mLockPatternUtils = lockPatternUtils;
@@ -255,7 +254,7 @@
             mSelectedUserInteractor = selectedUserInteractor;
             mUiEventLogger = uiEventLogger;
             mKeyguardKeyboardInteractor = keyguardKeyboardInteractor;
-            mMSDLPlayer = msdlPlayer;
+            mBouncerHapticPlayer = bouncerHapticPlayer;
             mUserActivityNotifier = userActivityNotifier;
         }
 
@@ -272,7 +271,7 @@
                         keyguardSecurityCallback, mLatencyTracker, mFalsingCollector,
                         emergencyButtonController, mMessageAreaControllerFactory,
                         mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
-                        mMSDLPlayer);
+                        mBouncerHapticPlayer);
             } else if (keyguardInputView instanceof KeyguardPasswordView) {
                 return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
@@ -280,14 +279,14 @@
                         mInputMethodManager, emergencyButtonController, mMainExecutor, mResources,
                         mFalsingCollector, mKeyguardViewController,
                         mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
-                        mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier);
+                        mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier);
             } else if (keyguardInputView instanceof KeyguardPINView) {
                 return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                         mLiftToActivateListener, emergencyButtonController, mFalsingCollector,
                         mDevicePostureController, mFeatureFlags, mSelectedUserInteractor,
-                        mUiEventLogger, mKeyguardKeyboardInteractor, mMSDLPlayer,
+                        mUiEventLogger, mKeyguardKeyboardInteractor, mBouncerHapticPlayer,
                         mUserActivityNotifier);
             } else if (keyguardInputView instanceof KeyguardSimPinView) {
                 return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
@@ -295,14 +294,14 @@
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                         mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
                         emergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
-                        mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier);
+                        mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier);
             } else if (keyguardInputView instanceof KeyguardSimPukView) {
                 return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
                         mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                         keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                         mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
                         emergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
-                        mKeyguardKeyboardInteractor, mMSDLPlayer, mUserActivityNotifier
+                        mKeyguardKeyboardInteractor, mBouncerHapticPlayer, mUserActivityNotifier
                 );
             }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 905fa09..4628ed7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -19,7 +19,6 @@
 import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -48,6 +47,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
 import com.android.systemui.Flags;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
@@ -56,8 +56,6 @@
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
-import com.google.android.msdl.domain.MSDLPlayer;
-
 import java.util.List;
 
 public class KeyguardPasswordViewController
@@ -138,12 +136,12 @@
             FeatureFlags featureFlags,
             SelectedUserInteractor selectedUserInteractor,
             KeyguardKeyboardInteractor keyguardKeyboardInteractor,
-            @Nullable MSDLPlayer msdlPlayer,
+            BouncerHapticPlayer bouncerHapticPlayer,
             UserActivityNotifier userActivityNotifier) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, falsingCollector,
-                emergencyButtonController, featureFlags, selectedUserInteractor, msdlPlayer,
-                userActivityNotifier);
+                emergencyButtonController, featureFlags, selectedUserInteractor,
+                bouncerHapticPlayer, userActivityNotifier);
         mKeyguardSecurityCallback = keyguardSecurityCallback;
         mInputMethodManager = inputMethodManager;
         mPostureController = postureController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index f74d93e..7fb6664 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -36,7 +36,7 @@
 import com.android.internal.widget.LockscreenCredential;
 import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.bouncer.ui.helper.BouncerHapticHelper;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingClassifier;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
@@ -44,8 +44,6 @@
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
-import com.google.android.msdl.domain.MSDLPlayer;
-
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -70,7 +68,6 @@
     private LockPatternView mLockPatternView;
     private CountDownTimer mCountdownTimer;
     private AsyncTask<?, ?, ?> mPendingLockCheck;
-    private MSDLPlayer mMSDLPlayer;
 
     private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() {
         @Override
@@ -80,7 +77,7 @@
     };
 
     private final LockPatternView.ExternalHapticsPlayer mExternalHapticsPlayer = () -> {
-        BouncerHapticHelper.INSTANCE.playPatternDotFeedback(mMSDLPlayer, mView);
+        mBouncerHapticPlayer.playPatternDotFeedback(mView);
     };
 
     /**
@@ -174,9 +171,8 @@
                 boolean isValidPattern) {
             boolean dismissKeyguard = mSelectedUserInteractor.getSelectedUserId() == userId;
             if (matched) {
-                BouncerHapticHelper.INSTANCE.playMSDLAuthenticationFeedback(
-                        /* authenticationSucceeded= */true,
-                        /* player =*/mMSDLPlayer
+                mBouncerHapticPlayer.playAuthenticationFeedback(
+                        /* authenticationSucceeded= */true
                 );
                 getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
                 if (dismissKeyguard) {
@@ -185,9 +181,8 @@
                     getKeyguardSecurityCallback().dismiss(true, userId, SecurityMode.Pattern);
                 }
             } else {
-                BouncerHapticHelper.INSTANCE.playMSDLAuthenticationFeedback(
-                        /* authenticationSucceeded= */false,
-                        /* player =*/mMSDLPlayer
+                mBouncerHapticPlayer.playAuthenticationFeedback(
+                        /* authenticationSucceeded= */false
                 );
                 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
                 if (isValidPattern) {
@@ -216,9 +211,11 @@
             EmergencyButtonController emergencyButtonController,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             DevicePostureController postureController, FeatureFlags featureFlags,
-            SelectedUserInteractor selectedUserInteractor, MSDLPlayer msdlPlayer) {
+            SelectedUserInteractor selectedUserInteractor, BouncerHapticPlayer bouncerHapticPlayer
+    ) {
         super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
-                messageAreaControllerFactory, featureFlags, selectedUserInteractor);
+                messageAreaControllerFactory, featureFlags, selectedUserInteractor,
+                bouncerHapticPlayer);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
@@ -228,7 +225,6 @@
                 featureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE));
         mLockPatternView = mView.findViewById(R.id.lockPatternView);
         mPostureController = postureController;
-        mMSDLPlayer = msdlPlayer;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index f575cf2..d999994 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -16,11 +16,9 @@
 
 package com.android.keyguard;
 
-import static com.android.systemui.Flags.msdlFeedback;
 import static com.android.systemui.Flags.pinInputFieldStyledFocusState;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
-import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.StateListDrawable;
@@ -37,14 +35,12 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
 import com.android.systemui.Flags;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.res.R;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
-import com.google.android.msdl.data.model.MSDLToken;
-import com.google.android.msdl.domain.MSDLPlayer;
-
 public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
         extends KeyguardAbsKeyInputViewController<T> {
 
@@ -83,12 +79,12 @@
             FeatureFlags featureFlags,
             SelectedUserInteractor selectedUserInteractor,
             KeyguardKeyboardInteractor keyguardKeyboardInteractor,
-            @Nullable MSDLPlayer msdlPlayer,
+            BouncerHapticPlayer bouncerHapticPlayer,
             UserActivityNotifier userActivityNotifier) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, falsingCollector,
-                emergencyButtonController, featureFlags, selectedUserInteractor, msdlPlayer,
-                userActivityNotifier);
+                emergencyButtonController, featureFlags, selectedUserInteractor,
+                bouncerHapticPlayer, userActivityNotifier);
         mLiftToActivateListener = liftToActivateListener;
         mFalsingCollector = falsingCollector;
         mKeyguardKeyboardInteractor = keyguardKeyboardInteractor;
@@ -110,16 +106,16 @@
                 return false;
             });
             button.setAnimationEnabled(showAnimations);
-            button.setMSDLPlayer(mMSDLPlayer);
+            button.setBouncerHapticHelper(mBouncerHapticPlayer);
         }
         mPasswordEntry.setOnKeyListener(mOnKeyListener);
         mPasswordEntry.setUserActivityListener(this::onUserInput);
 
         View deleteButton = mView.findViewById(R.id.delete_button);
-        if (msdlFeedback()) {
+        if (mBouncerHapticPlayer.isEnabled()) {
             deleteButton.setOnTouchListener((View view, MotionEvent event) -> {
-                if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mMSDLPlayer != null) {
-                    mMSDLPlayer.playToken(MSDLToken.KEYPRESS_DELETE, null);
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                    mBouncerHapticPlayer.playDeleteKeyPressFeedback();
                 }
                 return false;
             });
@@ -137,8 +133,8 @@
             if (mPasswordEntry.isEnabled()) {
                 mView.resetPasswordText(true /* animate */, true /* announce */);
             }
-            if (msdlFeedback() && mMSDLPlayer != null) {
-                mMSDLPlayer.playToken(MSDLToken.LONG_PRESS, null);
+            if (mBouncerHapticPlayer.isEnabled()) {
+                mBouncerHapticPlayer.playDeleteKeyLongPressedFeedback();
             } else {
                 mView.doHapticKeyClick();
             }
@@ -147,7 +143,7 @@
 
         View okButton = mView.findViewById(R.id.key_enter);
         if (okButton != null) {
-            if (!msdlFeedback()) {
+            if (!mBouncerHapticPlayer.isEnabled()) {
                 okButton.setOnTouchListener(mActionButtonTouchListener);
             }
             okButton.setOnClickListener(v -> {
@@ -201,7 +197,7 @@
 
         for (NumPadKey button : mView.getButtons()) {
             button.setOnTouchListener(null);
-            button.setMSDLPlayer(null);
+            button.setBouncerHapticHelper(null);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 3b5bf1a..d3c02e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
 
-import android.annotation.Nullable;
 import android.view.View;
 
 import com.android.internal.logging.UiEvent;
@@ -27,6 +26,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -34,8 +34,6 @@
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
-import com.google.android.msdl.domain.MSDLPlayer;
-
 public class KeyguardPinViewController
         extends KeyguardPinBasedInputViewController<KeyguardPINView> {
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -65,12 +63,12 @@
             DevicePostureController postureController, FeatureFlags featureFlags,
             SelectedUserInteractor selectedUserInteractor, UiEventLogger uiEventLogger,
             KeyguardKeyboardInteractor keyguardKeyboardInteractor,
-            @Nullable MSDLPlayer msdlPlayer,
+            BouncerHapticPlayer bouncerHapticPlayer,
             UserActivityNotifier userActivityNotifier) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
                 emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
-                keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier);
+                keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mPostureController = postureController;
         mLockPatternUtils = lockPatternUtils;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 47fe2b2..1c1acf8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -21,7 +21,6 @@
 import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.AlertDialog;
 import android.app.AlertDialog.Builder;
 import android.app.Dialog;
@@ -44,13 +43,12 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.res.R;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
-import com.google.android.msdl.domain.MSDLPlayer;
-
 public class KeyguardSimPinViewController
         extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
     public static final String TAG = "KeyguardSimPinView";
@@ -99,12 +97,12 @@
             EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags,
             SelectedUserInteractor selectedUserInteractor,
             KeyguardKeyboardInteractor keyguardKeyboardInteractor,
-            @Nullable MSDLPlayer msdlPlayer,
+            BouncerHapticPlayer bouncerHapticPlayer,
             UserActivityNotifier userActivityNotifier) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
                 emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
-                keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier);
+                keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mTelephonyManager = telephonyManager;
         mSimImageView = mView.findViewById(R.id.keyguard_sim);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index c688acb..9adc5ba 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -17,7 +17,6 @@
 package com.android.keyguard;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -39,13 +38,12 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.res.R;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
 
-import com.google.android.msdl.domain.MSDLPlayer;
-
 public class KeyguardSimPukViewController
         extends KeyguardPinBasedInputViewController<KeyguardSimPukView> {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -96,12 +94,12 @@
             EmergencyButtonController emergencyButtonController, FeatureFlags featureFlags,
             SelectedUserInteractor selectedUserInteractor,
             KeyguardKeyboardInteractor keyguardKeyboardInteractor,
-            @Nullable MSDLPlayer msdlPlayer,
+            BouncerHapticPlayer bouncerHapticPlayer,
             UserActivityNotifier userActivityNotifier) {
         super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                 messageAreaControllerFactory, latencyTracker, liftToActivateListener,
                 emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor,
-                keyguardKeyboardInteractor, msdlPlayer, userActivityNotifier);
+                keyguardKeyboardInteractor, bouncerHapticPlayer, userActivityNotifier);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mTelephonyManager = telephonyManager;
         mSimImageView = mView.findViewById(R.id.keyguard_sim);
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 4fb80de..7fe4ec8 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -15,7 +15,6 @@
  */
 package com.android.keyguard;
 
-import static com.android.systemui.Flags.msdlFeedback;
 import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY;
 
 import android.content.Context;
@@ -37,11 +36,9 @@
 import androidx.annotation.Nullable;
 
 import com.android.settingslib.Utils;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.res.R;
 
-import com.google.android.msdl.data.model.MSDLToken;
-import com.google.android.msdl.domain.MSDLPlayer;
-
 /**
  * Viewgroup for the bouncer numpad button, specifically for digits.
  */
@@ -62,7 +59,7 @@
     private NumPadAnimator mAnimator;
     private int mOrientation;
     @Nullable
-    private MSDLPlayer mMSDLPlayer;
+    private BouncerHapticPlayer mBouncerHapticPlayer;
 
     private View.OnClickListener mListener = new View.OnClickListener() {
         @Override
@@ -227,8 +224,8 @@
 
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
-        if (msdlFeedback() && mMSDLPlayer != null) {
-            mMSDLPlayer.playToken(MSDLToken.KEYPRESS_STANDARD, null);
+        if (mBouncerHapticPlayer != null && mBouncerHapticPlayer.isEnabled()) {
+            mBouncerHapticPlayer.playNumpadKeyFeedback();
         } else {
             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -255,7 +252,7 @@
         info.setTextEntryKey(true);
     }
 
-    public void setMSDLPlayer(@Nullable MSDLPlayer player) {
-        mMSDLPlayer = player;
+    public void setBouncerHapticHelper(@Nullable BouncerHapticPlayer bouncerHapticPlayer) {
+        mBouncerHapticPlayer = bouncerHapticPlayer;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
index aa96231..d4e74d3 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java
@@ -54,6 +54,7 @@
             STATUS_ICON_MIC_CAMERA_DISABLED,
             STATUS_ICON_PRIORITY_MODE_ON,
             STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
+            STATUS_ICON_LOCATION_ACTIVE,
     })
     public @interface StatusIconType {}
     public static final int STATUS_ICON_NOTIFICATIONS = 0;
@@ -64,6 +65,7 @@
     public static final int STATUS_ICON_MIC_CAMERA_DISABLED = 5;
     public static final int STATUS_ICON_PRIORITY_MODE_ON = 6;
     public static final int STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE = 7;
+    public static final int STATUS_ICON_LOCATION_ACTIVE = 8;
 
     private final Map<Integer, View> mStatusIcons = new HashMap<>();
     private Context mContext;
@@ -136,6 +138,8 @@
                 addDoubleShadow(fetchStatusIconForResId(R.id.dream_overlay_priority_mode)));
         mStatusIcons.put(STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE,
                 fetchStatusIconForResId(R.id.dream_overlay_assistant_attention_indicator));
+        mStatusIcons.put(STATUS_ICON_LOCATION_ACTIVE,
+                fetchStatusIconForResId(R.id.dream_overlay_location_active));
 
         mSystemStatusViewGroup = findViewById(R.id.dream_overlay_system_status);
         mExtraSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
@@ -151,6 +155,7 @@
             case STATUS_ICON_MIC_CAMERA_DISABLED -> "mic_camera_disabled";
             case STATUS_ICON_PRIORITY_MODE_ON -> "priority_mode_on";
             case STATUS_ICON_ASSISTANT_ATTENTION_ACTIVE -> "assistant_attention_active";
+            case STATUS_ICON_LOCATION_ACTIVE -> "location_active";
             default -> type + "(unknown)";
         };
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
index 04595a2..75024c6 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
@@ -27,6 +27,7 @@
 import android.util.PluralsMessageFormatter;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -39,6 +40,9 @@
 import com.android.systemui.dreams.DreamOverlayStatusBarItemsProvider.StatusBarItem;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.dagger.DreamLog;
+import com.android.systemui.privacy.PrivacyItem;
+import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CrossFadeHelper;
@@ -79,6 +83,7 @@
     private final DreamOverlayStateController mDreamOverlayStateController;
     private final UserTracker mUserTracker;
     private final WifiInteractor mWifiInteractor;
+    private final PrivacyItemController mPrivacyItemController;
     private final StatusBarWindowStateController mStatusBarWindowStateController;
     private final DreamOverlayStatusBarItemsProvider mStatusBarItemsProvider;
     private final Executor mMainExecutor;
@@ -131,6 +136,9 @@
     private final StatusBarWindowStateListener mStatusBarWindowStateListener =
             this::onSystemStatusBarStateChanged;
 
+    private final PrivacyItemController.Callback mPrivacyItemControllerCallback =
+            this::onPrivacyItemsChanged;
+
     @Inject
     public AmbientStatusBarViewController(
             AmbientStatusBarView view,
@@ -147,6 +155,7 @@
             DreamOverlayStateController dreamOverlayStateController,
             UserTracker userTracker,
             WifiInteractor wifiInteractor,
+            PrivacyItemController privacyItemController,
             CommunalSceneInteractor communalSceneInteractor,
             @DreamLog LogBuffer logBuffer) {
         super(view);
@@ -163,6 +172,7 @@
         mDreamOverlayStateController = dreamOverlayStateController;
         mUserTracker = userTracker;
         mWifiInteractor = wifiInteractor;
+        mPrivacyItemController = privacyItemController;
         mCommunalSceneInteractor = communalSceneInteractor;
         mLogger = new DreamLogger(logBuffer, TAG);
     }
@@ -174,10 +184,12 @@
         // Register to receive show/hide updates for the system status bar. Our custom status bar
         // needs to hide when the system status bar is showing to ovoid overlapping status bars.
         mStatusBarWindowStateController.addListener(mStatusBarWindowStateListener);
+        mPrivacyItemController.addCallback(mPrivacyItemControllerCallback);
     }
 
     @Override
     public void destroy() {
+        mPrivacyItemController.removeCallback(mPrivacyItemControllerCallback);
         mStatusBarWindowStateController.removeListener(mStatusBarWindowStateListener);
 
         super.destroy();
@@ -274,6 +286,11 @@
                 R.string.wifi_unavailable_dream_overlay_content_description);
     }
 
+    void updateLocationStatusIcon(boolean enabled) {
+        showIcon(AmbientStatusBarView.STATUS_ICON_LOCATION_ACTIVE, enabled,
+                R.string.location_active_dream_overlay_content_description);
+    }
+
     private void updateAlarmStatusIcon() {
         final AlarmManager.AlarmClockInfo alarm =
                 mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
@@ -369,6 +386,11 @@
         mMainExecutor.execute(this::updateVisibility);
     }
 
+    private void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
+        updateLocationStatusIcon(privacyItems.stream()
+                .anyMatch(item -> item.getPrivacyType() == PrivacyType.TYPE_LOCATION));
+    }
+
     private void onStatusBarItemsChanged(List<StatusBarItem> newItems) {
         mMainExecutor.execute(() -> {
             mExtraStatusBarItems.clear();
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
index d7a4863b..7647cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/flag/ComposeBouncerFlags.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.bouncer.shared.flag
 
 import com.android.systemui.Flags
+import com.android.systemui.flags.RefactorFlagUtils
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 
 object ComposeBouncerFlags {
@@ -34,6 +35,18 @@
     }
 
     /**
+     * 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
+    fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(
+            isEnabled,
+            "SceneContainerFlag || ComposeBouncerFlag"
+        )
+
+    /**
      * Returns `true` if only compose bouncer is enabled and scene container framework is not
      * enabled.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt
deleted file mode 100644
index 1faacff..0000000
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticHelper.kt
+++ /dev/null
@@ -1,73 +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.bouncer.ui.helper
-
-import android.view.HapticFeedbackConstants
-import android.view.View
-import com.android.keyguard.AuthInteractionProperties
-import com.android.systemui.Flags
-//noinspection CleanArchitectureDependencyViolation: Data layer only referenced for this enum class
-import com.google.android.msdl.data.model.MSDLToken
-import com.google.android.msdl.domain.MSDLPlayer
-
-/** A helper object to deliver haptic feedback in bouncer interactions. */
-object BouncerHapticHelper {
-
-    private val authInteractionProperties = AuthInteractionProperties()
-
-    /**
-     * Deliver MSDL feedback as a result of authenticating through a bouncer.
-     *
-     * @param[authenticationSucceeded] Whether the authentication was successful or not.
-     * @param[player] The [MSDLPlayer] that delivers the correct feedback.
-     */
-    fun playMSDLAuthenticationFeedback(
-        authenticationSucceeded: Boolean,
-        player: MSDLPlayer?,
-    ) {
-        if (player == null || !Flags.msdlFeedback()) {
-            return
-        }
-
-        val token =
-            if (authenticationSucceeded) {
-                MSDLToken.UNLOCK
-            } else {
-                MSDLToken.FAILURE
-            }
-        player.playToken(token, authInteractionProperties)
-    }
-
-    /**
-     * Deliver feedback when dragging through cells in the pattern bouncer. This function can play
-     * MSDL feedback using a [MSDLPlayer], or fallback to a default haptic feedback using the
-     * [View.performHapticFeedback] API and a [View].
-     *
-     * @param[player] [MSDLPlayer] for MSDL feedback.
-     * @param[view] A [View] for default haptic feedback using [View.performHapticFeedback]
-     */
-    fun playPatternDotFeedback(player: MSDLPlayer?, view: View?) {
-        if (player == null || !Flags.msdlFeedback()) {
-            view?.performHapticFeedback(
-                HapticFeedbackConstants.VIRTUAL_KEY,
-                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING,
-            )
-        } else {
-            player.playToken(MSDLToken.DRAG_INDICATOR)
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt
new file mode 100644
index 0000000..19e7537
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/helper/BouncerHapticPlayer.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bouncer.ui.helper
+
+import android.view.HapticFeedbackConstants
+import android.view.View
+import com.android.keyguard.AuthInteractionProperties
+import com.android.systemui.Flags
+//noinspection CleanArchitectureDependencyViolation: Data layer only referenced for this enum class
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.MSDLPlayer
+import javax.inject.Inject
+
+/**
+ * A helper class to deliver haptic feedback in bouncer interactions.
+ *
+ * @param[msdlPlayer] The [MSDLPlayer] used to deliver MSDL feedback.
+ */
+class BouncerHapticPlayer @Inject constructor(private val msdlPlayer: dagger.Lazy<MSDLPlayer>) {
+
+    private val authInteractionProperties by
+        lazy(LazyThreadSafetyMode.NONE) { AuthInteractionProperties() }
+
+    val isEnabled: Boolean
+        get() = Flags.msdlFeedback()
+
+    /**
+     * Deliver MSDL feedback as a result of authenticating through a bouncer.
+     *
+     * @param[authenticationSucceeded] Whether the authentication was successful or not.
+     */
+    fun playAuthenticationFeedback(authenticationSucceeded: Boolean) {
+        if (!isEnabled) return
+
+        val token =
+            if (authenticationSucceeded) {
+                MSDLToken.UNLOCK
+            } else {
+                MSDLToken.FAILURE
+            }
+        msdlPlayer.get().playToken(token, authInteractionProperties)
+    }
+
+    /**
+     * Deliver feedback when dragging through cells in the pattern bouncer. This function can play
+     * MSDL feedback using a [MSDLPlayer], or fallback to a default haptic feedback using the
+     * [View.performHapticFeedback] API and a [View].
+     *
+     * @param[view] A [View] for default haptic feedback using [View.performHapticFeedback]
+     */
+    fun playPatternDotFeedback(view: View?) {
+        if (!isEnabled) {
+            view?.performHapticFeedback(
+                HapticFeedbackConstants.VIRTUAL_KEY,
+                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING,
+            )
+        } else {
+            msdlPlayer.get().playToken(MSDLToken.DRAG_INDICATOR)
+        }
+    }
+
+    /** Deliver MSDL feedback when the delete key of the pin bouncer is pressed */
+    fun playDeleteKeyPressFeedback() = msdlPlayer.get().playToken(MSDLToken.KEYPRESS_DELETE)
+
+    /**
+     * Deliver MSDL feedback when the delete key of the pin bouncer is long-pressed
+     *
+     * @return whether MSDL feedback is allowed to play.
+     */
+    fun playDeleteKeyLongPressedFeedback() = msdlPlayer.get().playToken(MSDLToken.LONG_PRESS)
+
+    /** Deliver MSDL feedback when a numpad key is pressed on the pin bouncer */
+    fun playNumpadKeyFeedback() = msdlPlayer.get().playToken(MSDLToken.KEYPRESS_STANDARD)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
index d223657..73a8810 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
@@ -47,21 +47,9 @@
             launch {
                 authenticationInteractor.onAuthenticationResult.collect { authenticationSucceeded ->
                     if (authenticationSucceeded) {
-                        // Some dismiss actions require that keyguard be dismissed right away or
-                        // deferred until something else later on dismisses keyguard (eg. end of
-                        // a hide animation).
-                        val deferKeyguardDone =
-                            legacyInteractor.bouncerDismissAction?.onDismissAction?.onDismiss()
-                        legacyInteractor.setDismissAction(null, null)
-
-                        viewMediatorCallback?.let {
-                            val selectedUserId = selectedUserInteractor.getSelectedUserId()
-                            if (deferKeyguardDone == true) {
-                                it.keyguardDonePending(selectedUserId)
-                            } else {
-                                it.keyguardDone(selectedUserId)
-                            }
-                        }
+                        legacyInteractor.notifyKeyguardAuthenticatedPrimaryAuth(
+                            selectedUserInteractor.getSelectedUserId()
+                        )
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index df6ca9b..da29c62 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 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.res.R
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
@@ -265,6 +266,15 @@
         }
     }
 
+    /** Notifies that the user has pressed down on a digit button. */
+    fun onDigitButtonDown() {
+        if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
+            // Current PIN bouncer informs FalsingInteractor#avoidGesture() upon every Pin button
+            // touch.
+            super.onDown()
+        }
+    }
+
     @AssistedFactory
     interface Factory {
         fun create(
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index dcd4195..a62600d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -25,6 +25,7 @@
 public class FalsingCollectorFake implements FalsingCollector {
 
     public KeyEvent lastKeyEvent = null;
+    public boolean avoidGestureInvoked = false;
 
     @Override
     public void init() {
@@ -87,6 +88,16 @@
 
     @Override
     public void avoidGesture() {
+        avoidGestureInvoked = true;
+    }
+
+    /**
+     * @return whether {@link #avoidGesture()} was invoked.
+     */
+    public boolean wasLastGestureAvoided() {
+        boolean wasLastGestureAvoided = avoidGestureInvoked;
+        avoidGestureInvoked = false;
+        return wasLastGestureAvoided;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index 0e39a99..ec03227 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -21,8 +21,10 @@
 import android.util.SizeF
 import com.android.app.tracing.coroutines.withContext
 import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.widgets.AppWidgetHostListenerDelegate
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
 import com.android.systemui.communal.widgets.CommunalAppWidgetHostView
+import com.android.systemui.communal.widgets.WidgetInteractionHandler
 import com.android.systemui.dagger.qualifiers.UiBackground
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
@@ -33,6 +35,8 @@
 constructor(
     @UiBackground private val uiBgContext: CoroutineContext,
     private val appWidgetHost: CommunalAppWidgetHost,
+    private val interactionHandler: WidgetInteractionHandler,
+    private val listenerFactory: AppWidgetHostListenerDelegate.Factory,
 ) {
     suspend fun createWidget(
         context: Context,
@@ -40,18 +44,20 @@
         size: SizeF,
     ): CommunalAppWidgetHostView =
         withContext("$TAG#createWidget", uiBgContext) {
-            appWidgetHost
-                .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
-                .apply {
-                    updateAppWidgetSize(
-                        /* newOptions = */ Bundle(),
-                        /* minWidth = */ size.width.toInt(),
-                        /* minHeight = */ size.height.toInt(),
-                        /* maxWidth = */ size.width.toInt(),
-                        /* maxHeight = */ size.height.toInt(),
-                        /* ignorePadding = */ true,
-                    )
-                }
+            val view = CommunalAppWidgetHostView(context, interactionHandler)
+            view.setAppWidget(model.appWidgetId, model.providerInfo)
+            // Instead of setting the view as the listener directly, we wrap the view in a delegate
+            // which ensures the callbacks always get called on the main thread.
+            appWidgetHost.setListener(model.appWidgetId, listenerFactory.create(view))
+            view.updateAppWidgetSize(
+                /* newOptions = */ Bundle(),
+                /* minWidth = */ size.width.toInt(),
+                /* minHeight = */ size.height.toInt(),
+                /* maxWidth = */ size.width.toInt(),
+                /* maxHeight = */ size.height.toInt(),
+                /* ignorePadding = */ true,
+            )
+            view
         }
 
     private companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.kt
new file mode 100644
index 0000000..f341621
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/AppWidgetHostListenerDelegate.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.communal.widgets
+
+import android.appwidget.AppWidgetHost.AppWidgetHostListener
+import android.appwidget.AppWidgetProviderInfo
+import android.widget.RemoteViews
+import com.android.systemui.dagger.qualifiers.Main
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.concurrent.Executor
+
+/**
+ * Wrapper for an [AppWidgetHostListener] to ensure the callbacks are executed on the main thread.
+ */
+class AppWidgetHostListenerDelegate
+@AssistedInject
+constructor(
+    @Main private val mainExecutor: Executor,
+    @Assisted private val listener: AppWidgetHostListener,
+) : AppWidgetHostListener {
+
+    @AssistedFactory
+    interface Factory {
+        fun create(listener: AppWidgetHostListener): AppWidgetHostListenerDelegate
+    }
+
+    override fun onUpdateProviderInfo(appWidget: AppWidgetProviderInfo?) {
+        mainExecutor.execute { listener.onUpdateProviderInfo(appWidget) }
+    }
+
+    override fun updateAppWidget(views: RemoteViews?) {
+        mainExecutor.execute { listener.updateAppWidget(views) }
+    }
+
+    override fun onViewDataChanged(viewId: Int) {
+        mainExecutor.execute { listener.onViewDataChanged(viewId) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
index 10a565f..b46698e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt
@@ -17,11 +17,7 @@
 package com.android.systemui.communal.widgets
 
 import android.appwidget.AppWidgetHost
-import android.appwidget.AppWidgetHostView
-import android.appwidget.AppWidgetProviderInfo
 import android.content.Context
-import android.os.Looper
-import android.widget.RemoteViews
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
 import javax.annotation.concurrent.GuardedBy
@@ -36,11 +32,8 @@
     context: Context,
     private val backgroundScope: CoroutineScope,
     hostId: Int,
-    private val interactionHandler: RemoteViews.InteractionHandler,
-    looper: Looper,
     logBuffer: LogBuffer,
-) : AppWidgetHost(context, hostId, interactionHandler, looper) {
-
+) : AppWidgetHost(context, hostId) {
     private val logger = Logger(logBuffer, TAG)
 
     private val _appWidgetIdToRemove = MutableSharedFlow<Int>()
@@ -50,29 +43,6 @@
 
     @GuardedBy("observers") private val observers = mutableSetOf<Observer>()
 
-    override fun onCreateView(
-        context: Context,
-        appWidgetId: Int,
-        appWidget: AppWidgetProviderInfo?
-    ): AppWidgetHostView {
-        return CommunalAppWidgetHostView(context, interactionHandler)
-    }
-
-    /**
-     * Creates and returns a [CommunalAppWidgetHostView]. This method does the same thing as
-     * `createView`. The only difference is that the returned value will be casted to
-     * [CommunalAppWidgetHostView].
-     */
-    fun createViewForCommunal(
-        context: Context?,
-        appWidgetId: Int,
-        appWidget: AppWidgetProviderInfo?
-    ): CommunalAppWidgetHostView {
-        // `createView` internally calls `onCreateView` to create the view. We cannot override
-        // `createView`, but we are sure that the hostView is `CommunalAppWidgetHostView`
-        return createView(context, appWidgetId, appWidget) as CommunalAppWidgetHostView
-    }
-
     override fun onAppWidgetRemoved(appWidgetId: Int) {
         backgroundScope.launch {
             logger.i({ "App widget removed from system: $int1" }) { int1 = appWidgetId }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
index 684303ae..f4962085 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt
@@ -20,7 +20,6 @@
 import android.appwidget.AppWidgetManager
 import android.content.Context
 import android.content.res.Resources
-import android.os.Looper
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
@@ -46,18 +45,9 @@
         fun provideCommunalAppWidgetHost(
             @Application context: Context,
             @Background backgroundScope: CoroutineScope,
-            interactionHandler: WidgetInteractionHandler,
-            @Main looper: Looper,
             @CommunalLog logBuffer: LogBuffer,
         ): CommunalAppWidgetHost {
-            return CommunalAppWidgetHost(
-                context,
-                backgroundScope,
-                APP_WIDGET_HOST_ID,
-                interactionHandler,
-                looper,
-                logBuffer,
-            )
+            return CommunalAppWidgetHost(context, backgroundScope, APP_WIDGET_HOST_ID, logBuffer)
         }
 
         @SysUISingleton
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 7018f9d..dbd7f07 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
@@ -24,8 +24,11 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository
 import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.domain.interactor.SceneBackInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.pairwise
 import com.android.systemui.utils.coroutines.flow.mapLatestConflated
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -34,6 +37,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.map
@@ -59,6 +63,7 @@
     private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
     private val alternateBouncerInteractor: AlternateBouncerInteractor,
     private val dismissCallbackRegistry: DismissCallbackRegistry,
+    sceneBackInteractor: SceneBackInteractor,
 ) {
     /**
      * Whether the device is unlocked.
@@ -86,19 +91,40 @@
      * Note: This does not imply that the lockscreen is visible or not.
      */
     val isDeviceEntered: StateFlow<Boolean> =
-        sceneInteractor.currentScene
-            .filter { currentScene ->
-                currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
-            }
-            .mapLatestConflated { scene ->
-                if (scene == Scenes.Gone) {
-                    // Make sure device unlock status is definitely unlocked before we consider the
-                    // device "entered".
-                    deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
-                    true
-                } else {
-                    false
-                }
+        combine(
+                // This flow emits true when the currentScene switches to Gone for the first time
+                // after having been on Lockscreen.
+                sceneInteractor.currentScene
+                    .filter { currentScene ->
+                        currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
+                    }
+                    .mapLatestConflated { scene ->
+                        if (scene == Scenes.Gone) {
+                            // Make sure device unlock status is definitely unlocked before we
+                            // consider the device "entered".
+                            deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
+                            true
+                        } else {
+                            false
+                        }
+                    },
+                // This flow emits true only if the bottom of the navigation back stack has been
+                // switched from Lockscreen to Gone. In other words, only if the device was unlocked
+                // while visiting at least one scene "above" the Lockscreen scene.
+                sceneBackInteractor.backStack
+                    // The bottom of the back stack, which is Lockscreen, Gone, or null if empty.
+                    .map { it.asIterable().lastOrNull() }
+                    // Filter out cases where the stack changes but the bottom remains unchanged.
+                    .distinctUntilChanged()
+                    // Detect changes of the bottom of the stack, start with null, so the first
+                    // update emits a value and the logic doesn't need to wait for a second value
+                    // before emitting something.
+                    .pairwise(initialValue = null)
+                    // Replacing a bottom of the stack that was Lockscreen with Gone constitutes a
+                    // "device entered" event.
+                    .map { (from, to) -> from == Scenes.Lockscreen && to == Scenes.Gone },
+            ) { enteredDirectly, enteredOnBackStack ->
+                enteredOnBackStack || enteredDirectly
             }
             .stateIn(
                 scope = applicationScope,
@@ -129,7 +155,7 @@
                 },
                 isLockscreenEnabled,
                 deviceUnlockedInteractor.deviceUnlockStatus,
-                isDeviceEntered
+                isDeviceEntered,
             ) { isNoneAuthMethod, isLockscreenEnabled, deviceUnlockStatus, isDeviceEntered ->
                 val isSwipeAuthMethod = isNoneAuthMethod && isLockscreenEnabled
                 (isSwipeAuthMethod ||
@@ -155,9 +181,7 @@
      *   canceled
      */
     @JvmOverloads
-    fun attemptDeviceEntry(
-        callback: IKeyguardDismissCallback? = null,
-    ) {
+    fun attemptDeviceEntry(callback: IKeyguardDismissCallback? = null) {
         callback?.let { dismissCallbackRegistry.addCallback(it) }
 
         // TODO (b/307768356),
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 1f5878b..a327e4a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -28,7 +28,6 @@
 import android.view.Display
 import com.android.app.tracing.FlowTracing.traceEach
 import com.android.app.tracing.traceSection
-import com.android.systemui.Flags
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -51,7 +50,6 @@
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.scan
-import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.flow.stateIn
 
 /** Provides a [Flow] of [Display] as returned by [DisplayManager]. */
@@ -102,7 +100,7 @@
     private val displayManager: DisplayManager,
     @Background backgroundHandler: Handler,
     @Background bgApplicationScope: CoroutineScope,
-    @Background backgroundCoroutineDispatcher: CoroutineDispatcher
+    @Background backgroundCoroutineDispatcher: CoroutineDispatcher,
 ) : DisplayRepository {
     private val allDisplayEvents: Flow<DisplayEvent> =
         conflatedCallbackFlow {
@@ -139,70 +137,55 @@
     override val displayAdditionEvent: Flow<Display?> =
         allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map { getDisplay(it.displayId) }
 
-    // TODO: b/345472038 - Delete after the flag is ramped up.
-    private val oldEnabledDisplays: Flow<Set<Display>> =
-        allDisplayEvents
-            .map { getDisplays() }
-            .shareIn(bgApplicationScope, started = SharingStarted.WhileSubscribed(), replay = 1)
+    // This is necessary because there might be multiple displays, and we could
+    // have missed events for those added before this process or flow started.
+    // Note it causes a binder call from the main thread (it's traced).
+    private val initialDisplays: Set<Display> =
+        traceSection("$TAG#initialDisplays") { displayManager.displays?.toSet() ?: emptySet() }
+    private val initialDisplayIds = initialDisplays.map { display -> display.displayId }.toSet()
 
     /** Propagate to the listeners only enabled displays */
     private val enabledDisplayIds: Flow<Set<Int>> =
-        if (Flags.enableEfficientDisplayRepository()) {
-                allDisplayEvents
-                    .scan(initial = emptySet()) { previousIds: Set<Int>, event: DisplayEvent ->
-                        val id = event.displayId
-                        when (event) {
-                            is DisplayEvent.Removed -> previousIds - id
-                            is DisplayEvent.Added,
-                            is DisplayEvent.Changed -> previousIds + id
-                        }
-                    }
-                    .distinctUntilChanged()
-                    .stateIn(
-                        bgApplicationScope,
-                        SharingStarted.WhileSubscribed(),
-                        // This is necessary because there might be multiple displays, and we could
-                        // have missed events for those added before this process or flow started.
-                        // Note it causes a binder call from the main thread (it's traced).
-                        getDisplays().map { display -> display.displayId }.toSet(),
-                    )
-            } else {
-                oldEnabledDisplays.map { enabledDisplaysSet ->
-                    enabledDisplaysSet.map { it.displayId }.toSet()
+        allDisplayEvents
+            .scan(initial = initialDisplayIds) { previousIds: Set<Int>, event: DisplayEvent ->
+                val id = event.displayId
+                when (event) {
+                    is DisplayEvent.Removed -> previousIds - id
+                    is DisplayEvent.Added,
+                    is DisplayEvent.Changed -> previousIds + id
                 }
             }
+            .distinctUntilChanged()
+            .stateIn(bgApplicationScope, SharingStarted.WhileSubscribed(), initialDisplayIds)
             .debugLog("enabledDisplayIds")
 
     private val defaultDisplay by lazy {
         getDisplay(Display.DEFAULT_DISPLAY) ?: error("Unable to get default display.")
     }
+
     /**
      * Represents displays that went though the [DisplayListener.onDisplayAdded] callback.
      *
      * Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
      */
     private val enabledDisplays: Flow<Set<Display>> =
-        if (Flags.enableEfficientDisplayRepository()) {
-            enabledDisplayIds
-                .mapElementsLazily { displayId -> getDisplay(displayId) }
-                .onEach {
-                    if (it.isEmpty()) Log.wtf(TAG, "No enabled displays. This should never happen.")
-                }
-                .flowOn(backgroundCoroutineDispatcher)
-                .debugLog("enabledDisplays")
-                .stateIn(
-                    bgApplicationScope,
-                    started = SharingStarted.WhileSubscribed(),
-                    // This triggers a single binder call on the UI thread per process. The
-                    // alternative would be to use sharedFlows, but they are prohibited due to
-                    // performance concerns.
-                    // Ultimately, this is a trade-off between a one-time UI thread binder call and
-                    // the constant overhead of sharedFlows.
-                    initialValue = getDisplays()
-                )
-        } else {
-            oldEnabledDisplays
-        }
+        enabledDisplayIds
+            .mapElementsLazily { displayId -> getDisplay(displayId) }
+            .onEach {
+                if (it.isEmpty()) Log.wtf(TAG, "No enabled displays. This should never happen.")
+            }
+            .flowOn(backgroundCoroutineDispatcher)
+            .debugLog("enabledDisplays")
+            .stateIn(
+                bgApplicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                // This triggers a single binder call on the UI thread per process. The
+                // alternative would be to use sharedFlows, but they are prohibited due to
+                // performance concerns.
+                // Ultimately, this is a trade-off between a one-time UI thread binder call and
+                // the constant overhead of sharedFlows.
+                initialValue = initialDisplays,
+            )
 
     /**
      * Represents displays that went though the [DisplayListener.onDisplayAdded] callback.
@@ -211,10 +194,7 @@
      */
     override val displays: Flow<Set<Display>> = enabledDisplays
 
-    private fun getDisplays(): Set<Display> =
-        traceSection("$TAG#getDisplays()") { displayManager.displays?.toSet() ?: emptySet() }
-
-    private val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
+    val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
     private val ignoredDisplayIds: Flow<Set<Int>> = _ignoredDisplayIds.debugLog("ignoredDisplayIds")
 
     private fun getInitialConnectedDisplays(): Set<Int> =
@@ -271,7 +251,7 @@
                 // the flow starts being collected. This is to ensure the call to get displays (an
                 // IPC) happens in the background instead of when this object
                 // is instantiated.
-                initialValue = emptySet()
+                initialValue = emptySet(),
             )
 
     private val connectedExternalDisplayIds: Flow<Set<Int>> =
@@ -308,7 +288,7 @@
                         TAG,
                         "combining enabled=$enabledDisplaysIds, " +
                             "connectedExternalDisplayIds=$connectedExternalDisplayIds, " +
-                            "ignored=$ignoredDisplayIds"
+                            "ignored=$ignoredDisplayIds",
                     )
                 }
                 connectedExternalDisplayIds - enabledDisplaysIds - ignoredDisplayIds
@@ -382,7 +362,7 @@
             val previousSet: Set<T>,
             // Caches T values from the previousSet that were already converted to V
             val valueMap: Map<T, V>,
-            val resultSet: Set<V>
+            val resultSet: Set<V>,
         )
 
         val emptyInitialState = State(emptySet<T>(), emptyMap(), emptySet<V>())
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index dcca12f..beec348 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -736,14 +736,13 @@
     val interactionSource = remember { MutableInteractionSource() }
     val isFocused by interactionSource.collectIsFocusedAsState()
 
-    Surface(
+    SelectableShortcutSurface(
         selected = selected,
         onClick = onClick,
         modifier =
             Modifier.semantics { role = Role.Tab }
                 .heightIn(min = 64.dp)
                 .fillMaxWidth()
-                .focusable(interactionSource = interactionSource)
                 .outlineFocusModifier(
                     isFocused = isFocused,
                     focusColor = MaterialTheme.colorScheme.secondary,
@@ -752,6 +751,7 @@
                 ),
         shape = RoundedCornerShape(28.dp),
         color = colors.containerColor(selected).value,
+        interactionSource = interactionSource
     ) {
         Row(Modifier.padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) {
             ShortcutCategoryIcon(
@@ -860,14 +860,12 @@
 private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick: () -> Unit) {
     val interactionSource = remember { MutableInteractionSource() }
     val isFocused by interactionSource.collectIsFocusedAsState()
-    Surface(
+    ClickableShortcutSurface(
         onClick = onClick,
         shape = RoundedCornerShape(24.dp),
         color = Color.Transparent,
-        modifier =
-            Modifier.semantics { role = Role.Button }
-                .fillMaxWidth()
-                .focusable(interactionSource = interactionSource)
+        modifier = Modifier.semantics { role = Role.Button }.fillMaxWidth(),
+        interactionSource = interactionSource
     ) {
         Row(
             modifier =
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
new file mode 100644
index 0000000..3ba3bd8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.shortcut.ui.composable
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.LocalAbsoluteTonalElevation
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.LocalTonalElevationEnabled
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.contentColorFor
+import androidx.compose.material3.minimumInteractiveComponentSize
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.NonRestartableComposable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.android.compose.modifiers.thenIf
+
+/**
+ * A selectable surface with no default focus/hover indications.
+ *
+ * This composable is similar to [androidx.compose.material3.Surface], but removes default
+ * focus/hover states to enable custom implementations.
+ */
+@Composable
+@NonRestartableComposable
+fun SelectableShortcutSurface(
+    selected: Boolean,
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    shape: Shape = RectangleShape,
+    color: Color = MaterialTheme.colorScheme.surface,
+    contentColor: Color = contentColorFor(color),
+    tonalElevation: Dp = 0.dp,
+    shadowElevation: Dp = 0.dp,
+    border: BorderStroke? = null,
+    interactionSource: MutableInteractionSource? = null,
+    content: @Composable () -> Unit
+) {
+    @Suppress("NAME_SHADOWING")
+    val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
+    val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
+    CompositionLocalProvider(
+        LocalContentColor provides contentColor,
+        LocalAbsoluteTonalElevation provides absoluteElevation
+    ) {
+        Box(
+            modifier =
+                modifier
+                    .minimumInteractiveComponentSize()
+                    .surface(
+                        shape = shape,
+                        backgroundColor =
+                            surfaceColorAtElevation(color = color, elevation = absoluteElevation),
+                        border = border,
+                        shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() }
+                    )
+                    .selectable(
+                        selected = selected,
+                        interactionSource = interactionSource,
+                        indication = null,
+                        enabled = enabled,
+                        onClick = onClick
+                    ),
+            propagateMinConstraints = true
+        ) {
+            content()
+        }
+    }
+}
+
+/**
+ * A clickable surface with no default focus/hover indications.
+ *
+ * This composable is similar to [androidx.compose.material3.Surface], but removes default
+ * focus/hover states to enable custom implementations.
+ */
+@Composable
+@NonRestartableComposable
+fun ClickableShortcutSurface(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    shape: Shape = RectangleShape,
+    color: Color = MaterialTheme.colorScheme.surface,
+    contentColor: Color = contentColorFor(color),
+    tonalElevation: Dp = 0.dp,
+    shadowElevation: Dp = 0.dp,
+    border: BorderStroke? = null,
+    interactionSource: MutableInteractionSource? = null,
+    content: @Composable () -> Unit
+) {
+    @Suppress("NAME_SHADOWING")
+    val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
+    val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
+    CompositionLocalProvider(
+        LocalContentColor provides contentColor,
+        LocalAbsoluteTonalElevation provides absoluteElevation
+    ) {
+        Box(
+            modifier =
+                modifier
+                    .minimumInteractiveComponentSize()
+                    .surface(
+                        shape = shape,
+                        backgroundColor =
+                            surfaceColorAtElevation(color = color, elevation = absoluteElevation),
+                        border = border,
+                        shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() }
+                    )
+                    .clickable(
+                        interactionSource = interactionSource,
+                        indication = null,
+                        enabled = enabled,
+                        onClick = onClick
+                    ),
+            propagateMinConstraints = true
+        ) {
+            content()
+        }
+    }
+}
+
+@Composable
+private fun surfaceColorAtElevation(color: Color, elevation: Dp): Color {
+    return MaterialTheme.colorScheme.applyTonalElevation(color, elevation)
+}
+
+@Composable
+internal fun ColorScheme.applyTonalElevation(backgroundColor: Color, elevation: Dp): Color {
+    val tonalElevationEnabled = LocalTonalElevationEnabled.current
+    return if (backgroundColor == surface && tonalElevationEnabled) {
+        surfaceColorAtElevation(elevation)
+    } else {
+        backgroundColor
+    }
+}
+
+/**
+ * Applies surface-related modifiers to a composable.
+ *
+ * This function adds background, border, and shadow effects to a composable. Also ensure the
+ * composable is clipped to the given shape.
+ *
+ * @param shape The shape to apply to the composable's background, border, and clipping.
+ * @param backgroundColor The background color to apply to the composable.
+ * @param border An optional border to draw around the composable.
+ * @param shadowElevation The size of the shadow below the surface. To prevent shadow creep, only
+ *   apply shadow elevation when absolutely necessary, such as when the surface requires visual
+ *   separation from a patterned background. Note that It will not affect z index of the Surface. If
+ *   you want to change the drawing order you can use `Modifier.zIndex`.
+ * @return The modified Modifier instance with surface-related modifiers applied.
+ */
+@Stable
+private fun Modifier.surface(
+    shape: Shape,
+    backgroundColor: Color,
+    border: BorderStroke?,
+    shadowElevation: Float,
+): Modifier {
+    return this.thenIf(shadowElevation > 0f) {
+            Modifier.graphicsLayer(shadowElevation = shadowElevation, shape = shape, clip = false)
+        }
+        .thenIf(border != null) { Modifier.border(border!!, shape) }
+        .background(color = backgroundColor, shape = shape)
+        .clip(shape)
+}
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 228e01e..cd5daf9 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
@@ -108,7 +108,7 @@
             .transition(
                 edge = Edge.create(from = KeyguardState.LOCKSCREEN, to = Scenes.Gone),
                 edgeWithoutSceneContainer =
-                    Edge.create(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+                    Edge.create(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE),
             )
             .map<TransitionStep, Boolean?> {
                 true // Make the surface visible during LS -> GONE transitions.
@@ -162,7 +162,7 @@
                 .collect {
                     startTransitionTo(
                         KeyguardState.PRIMARY_BOUNCER,
-                        ownerReason = "#listenForLockscreenToPrimaryBouncer"
+                        ownerReason = "#listenForLockscreenToPrimaryBouncer",
                     )
                 }
         }
@@ -238,7 +238,7 @@
                                             getDefaultAnimatorForTransitionsToState(
                                                     KeyguardState.LOCKSCREEN
                                                 )
-                                                .apply { duration = 0 }
+                                                .apply { duration = 0 },
                                     )
                                 )
                             }
@@ -249,6 +249,8 @@
                         if (
                             // Use currentTransitionInfo to decide whether to start the transition.
                             currentTransitionInfo.to == KeyguardState.LOCKSCREEN &&
+                                shadeExpansion > 0f &&
+                                shadeExpansion < 1f &&
                                 shadeRepository.legacyShadeTracking.value &&
                                 !isKeyguardUnlocked &&
                                 statusBarState == KEYGUARD
@@ -257,7 +259,7 @@
                                 startTransitionTo(
                                     toState = KeyguardState.PRIMARY_BOUNCER,
                                     animator = null, // transition will be manually controlled,
-                                    ownerReason = "#listenForLockscreenToPrimaryBouncerDragging"
+                                    ownerReason = "#listenForLockscreenToPrimaryBouncerDragging",
                                 )
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index 60c5386..8495778 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -164,7 +164,7 @@
     }
 
     fun runAfterKeyguardGone(runnable: Runnable) {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+        if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
         setDismissAction(
             DismissAction.RunAfterKeyguardGone(
                 dismissAction = { runnable.run() },
@@ -176,18 +176,18 @@
     }
 
     fun setDismissAction(dismissAction: DismissAction) {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+        if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
         repository.dismissAction.value.onCancelAction.run()
         repository.setDismissAction(dismissAction)
     }
 
     fun handleDismissAction() {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+        if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
         repository.setDismissAction(DismissAction.None)
     }
 
     suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return
+        if (ComposeBouncerFlags.isUnexpectedlyInLegacyMode()) return
         dismissInteractor.setKeyguardDone(keyguardDoneTiming)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index 7e13d22..4b62eab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -181,7 +181,7 @@
         }
         .stateIn(
             scope = applicationScope,
-            started = SharingStarted.WhileSubscribed(),
+            started = SharingStarted.Eagerly,
             initialValue =
                 KeyguardQuickAffordanceViewModel(
                     slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()
@@ -202,7 +202,7 @@
         }
         .stateIn(
             scope = applicationScope,
-            started = SharingStarted.WhileSubscribed(),
+            started = SharingStarted.Eagerly,
             initialValue =
                 KeyguardQuickAffordanceViewModel(
                     slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId()
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 eaa61a1..38ca888 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
@@ -36,6 +36,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
 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.KeyguardState.PRIMARY_BOUNCER
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
 import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
@@ -174,6 +175,9 @@
                     keyguardTransitionInteractor.isInTransition(
                         Edge.create(from = LOCKSCREEN, to = DREAMING)
                     ),
+                    keyguardTransitionInteractor.isInTransition(
+                        Edge.create(from = LOCKSCREEN, to = OCCLUDED)
+                    ),
                 ),
                 isOnLockscreen,
                 shadeInteractor.qsExpansion,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index bf9ef8c..8505a784 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -1202,13 +1202,17 @@
             commonViewModels.forEach { viewModel ->
                 when (viewModel) {
                     is MediaCommonViewModel.MediaControl -> {
-                        controllerById[viewModel.instanceId.toString()]?.mediaViewHolder?.let {
-                            mediaContent.addView(it.player)
+                        controllerById[viewModel.instanceId.toString()]?.let {
+                            it.widthInSceneContainerPx = widthInSceneContainerPx
+                            it.heightInSceneContainerPx = heightInSceneContainerPx
+                            mediaContent.addView(it.mediaViewHolder?.player)
                         }
                     }
                     is MediaCommonViewModel.MediaRecommendations -> {
-                        controllerById[viewModel.key]?.recommendationViewHolder?.let {
-                            mediaContent.addView(it.recommendations)
+                        controllerById[viewModel.key]?.let {
+                            it.widthInSceneContainerPx = widthInSceneContainerPx
+                            it.heightInSceneContainerPx = heightInSceneContainerPx
+                            mediaContent.addView(it.recommendationViewHolder?.recommendations)
                         }
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 89d76f0..f7a505a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -1335,14 +1335,16 @@
     public void setBackAnimation(@Nullable BackAnimation backAnimation) {
         mBackAnimation = backAnimation;
         if (backAnimation != null) {
-            backAnimation.setPilferPointerCallback(this::pilferPointers);
+            final Executor uiThreadExecutor = mUiThreadContext.getExecutor();
+            backAnimation.setPilferPointerCallback(
+                    () -> uiThreadExecutor.execute(this::pilferPointers));
             backAnimation.setTopUiRequestCallback(
-                    (requestTopUi, tag) -> mUiThreadContext.getExecutor().execute(() ->
+                    (requestTopUi, tag) -> uiThreadExecutor.execute(() ->
                             mNotificationShadeWindowController.setRequestTopUi(requestTopUi, tag)));
             updateBackAnimationThresholds();
             if (mLightBarControllerProvider.get() != null) {
                 mBackAnimation.setStatusBarCustomizer((appearance) ->
-                        mUiThreadContext.getExecutor().execute(() ->
+                        uiThreadExecutor.execute(() ->
                             mLightBarControllerProvider.get()
                                     .customizeStatusBarAppearance(appearance)));
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a402a9d..ac49e91 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,10 +101,10 @@
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
-import com.android.systemui.scene.shared.model.SceneFamilies;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -158,6 +158,7 @@
     private final ScreenPinningRequest mScreenPinningRequest;
     private final NotificationShadeWindowController mStatusBarWinController;
     private final Provider<SceneInteractor> mSceneInteractor;
+    private final Provider<ShadeInteractor> mShadeInteractor;
 
     private final KeyboardTouchpadEduStatsInteractor mKeyboardTouchpadEduStatsInteractor;
 
@@ -246,11 +247,8 @@
                             }
                         } else if (action == ACTION_UP) {
                             // Gesture was too short to be picked up by scene container touch
-                            // handling; programmatically start the transition to shade scene.
-                            mSceneInteractor.get().changeScene(
-                                    SceneFamilies.NotifShade,
-                                    "short launcher swipe"
-                            );
+                            // handling; programmatically start the transition to the shade.
+                            mShadeInteractor.get().expandNotificationShade("short launcher swipe");
                         }
                     }
                     event.recycle();
@@ -267,10 +265,7 @@
                         mSceneInteractor.get().onRemoteUserInputStarted(
                                 "trackpad swipe");
                     } else if (action == ACTION_UP) {
-                        mSceneInteractor.get().changeScene(
-                                SceneFamilies.NotifShade,
-                                "short trackpad swipe"
-                        );
+                        mShadeInteractor.get().expandNotificationShade("short trackpad swipe");
                     }
                     mStatusBarWinController.getWindowRootView().dispatchTouchEvent(event);
                 } else {
@@ -652,6 +647,7 @@
             NotificationShadeWindowController statusBarWinController,
             SysUiState sysUiState,
             Provider<SceneInteractor> sceneInteractor,
+            Provider<ShadeInteractor> shadeInteractor,
             UserTracker userTracker,
             UserManager userManager,
             WakefulnessLifecycle wakefulnessLifecycle,
@@ -688,6 +684,7 @@
         mScreenPinningRequest = screenPinningRequest;
         mStatusBarWinController = statusBarWinController;
         mSceneInteractor = sceneInteractor;
+        mShadeInteractor = shadeInteractor;
         mUserTracker = userTracker;
         mConnectionBackoffAttempts = 0;
         mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
index 2d40845..afb72f0 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
@@ -71,6 +71,12 @@
         logger.logSceneBackStack(backStack.value.asIterable())
     }
 
+    /** Applies the given [transform] to the back stack. */
+    fun updateBackStack(transform: (SceneStack) -> SceneStack) {
+        _backStack.update { stack -> transform(stack) }
+        logger.logSceneBackStack(backStack.value.asIterable())
+    }
+
     private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? {
         val fromDistance =
             checkNotNull(sceneContainerConfig.navigationDistances[from]) {
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 18767f5..c5e0ccc 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
@@ -45,7 +45,6 @@
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor
 import com.android.systemui.model.SceneContainerPlugin
 import com.android.systemui.model.SysUiState
@@ -55,6 +54,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.scene.data.model.asIterable
+import com.android.systemui.scene.data.model.sceneStackOf
 import com.android.systemui.scene.domain.interactor.SceneBackInteractor
 import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -118,7 +118,6 @@
     private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
     private val bouncerInteractor: BouncerInteractor,
     private val keyguardInteractor: KeyguardInteractor,
-    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val sysUiState: SysUiState,
     @DisplayId private val displayId: Int,
     private val sceneLogger: SceneLogger,
@@ -281,6 +280,8 @@
         applicationScope.launch {
             sceneInteractor.currentScene.collectLatest { currentScene ->
                 if (currentScene == Scenes.Lockscreen) {
+                    // Wait for the screen to be on
+                    powerInteractor.isAwake.first { it }
                     // Wait for surface to become visible
                     windowMgrLockscreenVisInteractor.surfaceBehindVisibility.first { it }
                     // Make sure the device is actually unlocked before force-changing the scene
@@ -419,7 +420,20 @@
                                         " didn't need to be left open"
                             } else {
                                 val prevScene = previousScene.value
-                                (prevScene ?: Scenes.Gone) to
+                                val targetScene = prevScene ?: Scenes.Gone
+                                if (targetScene != Scenes.Gone) {
+                                    sceneBackInteractor.updateBackStack { stack ->
+                                        val list = stack.asIterable().toMutableList()
+                                        check(list.last() == Scenes.Lockscreen) {
+                                            "The bottommost/last SceneKey of the back stack isn't" +
+                                                " the Lockscreen scene like expected. The back" +
+                                                " stack is $stack."
+                                        }
+                                        list[list.size - 1] = Scenes.Gone
+                                        sceneStackOf(*list.toTypedArray())
+                                    }
+                                }
+                                targetScene to
                                     "device was unlocked with primary bouncer showing," +
                                         " from sceneKey=$prevScene"
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index d4e711e..663ba20 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -41,7 +41,6 @@
 import androidx.exifinterface.media.ExifInterface;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.flags.FeatureFlags;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -94,12 +93,10 @@
     private final ContentResolver mResolver;
     private CompressFormat mCompressFormat = CompressFormat.PNG;
     private int mQuality = 100;
-    private final FeatureFlags mFlags;
 
     @Inject
-    public ImageExporter(ContentResolver resolver, FeatureFlags flags) {
+    public ImageExporter(ContentResolver resolver) {
         mResolver = resolver;
-        mFlags = flags;
     }
 
     /**
@@ -161,8 +158,7 @@
         ZonedDateTime captureTime = ZonedDateTime.now(ZoneId.systemDefault());
         return export(executor,
                 new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
-                        mQuality, /* publish */ true, owner, mFlags,
-                        createFilename(captureTime, mCompressFormat, displayId)));
+                        mQuality, owner, createFilename(captureTime, mCompressFormat, displayId)));
     }
 
     /**
@@ -184,7 +180,8 @@
                         bitmap,
                         ZonedDateTime.now(ZoneId.systemDefault()),
                         format,
-                        mQuality, /* publish */ true, owner, mFlags,
+                        mQuality,
+                        owner,
                         createSystemFileDisplayName(fileName, format),
                         true /* allowOverwrite */));
     }
@@ -199,8 +196,7 @@
     public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
             ZonedDateTime captureTime, UserHandle owner, int displayId) {
         return export(executor, new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
-                mQuality, /* publish */ true, owner, mFlags,
-                createFilename(captureTime, mCompressFormat, displayId)));
+                mQuality, owner, createFilename(captureTime, mCompressFormat, displayId)));
     }
 
     /**
@@ -213,8 +209,7 @@
     ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
             ZonedDateTime captureTime, UserHandle owner, String fileName) {
         return export(executor, new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
-                mQuality, /* publish */ true, owner, mFlags,
-                createSystemFileDisplayName(fileName, mCompressFormat)));
+                mQuality, owner, createSystemFileDisplayName(fileName, mCompressFormat)));
     }
 
     /**
@@ -249,7 +244,6 @@
         public String fileName;
         public long timestamp;
         public CompressFormat format;
-        public boolean published;
 
         @Override
         public String toString() {
@@ -259,7 +253,6 @@
             sb.append(", fileName='").append(fileName).append('\'');
             sb.append(", timestamp=").append(timestamp);
             sb.append(", format=").append(format);
-            sb.append(", published=").append(published);
             sb.append('}');
             return sb.toString();
         }
@@ -274,8 +267,6 @@
         private final int mQuality;
         private final UserHandle mOwner;
         private final String mFileName;
-        private final boolean mPublish;
-        private final FeatureFlags mFlags;
 
         /**
          * This variable specifies the behavior when a file to be exported has a same name and
@@ -287,15 +278,14 @@
         private final boolean mAllowOverwrite;
 
         Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
-                CompressFormat format, int quality, boolean publish, UserHandle owner,
-                FeatureFlags flags, String fileName) {
-            this(resolver, requestId, bitmap, captureTime, format, quality, publish, owner, flags,
-                    fileName, false /* allowOverwrite */);
+                CompressFormat format, int quality, UserHandle owner, String fileName) {
+            this(resolver, requestId, bitmap, captureTime, format, quality, owner, fileName,
+                    false /* allowOverwrite */);
         }
 
         Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
-                CompressFormat format, int quality, boolean publish, UserHandle owner,
-                FeatureFlags flags, String fileName, boolean allowOverwrite) {
+                CompressFormat format, int quality, UserHandle owner,
+                String fileName, boolean allowOverwrite) {
             mResolver = resolver;
             mRequestId = requestId;
             mBitmap = bitmap;
@@ -304,8 +294,6 @@
             mQuality = quality;
             mOwner = owner;
             mFileName = fileName;
-            mPublish = publish;
-            mFlags = flags;
             mAllowOverwrite = allowOverwrite;
         }
 
@@ -320,7 +308,7 @@
                     start = Instant.now();
                 }
 
-                uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner, mFlags,
+                uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner,
                         mAllowOverwrite);
                 throwIfInterrupted();
 
@@ -332,10 +320,7 @@
                 writeExif(mResolver, uri, mRequestId, width, height, mCaptureTime);
                 throwIfInterrupted();
 
-                if (mPublish) {
-                    publishEntry(mResolver, uri);
-                    result.published = true;
-                }
+                publishEntry(mResolver, uri);
 
                 result.timestamp = mCaptureTime.toInstant().toEpochMilli();
                 result.requestId = mRequestId;
@@ -365,7 +350,7 @@
     }
 
     private static Uri createEntry(ContentResolver resolver, CompressFormat format,
-            ZonedDateTime time, String fileName, UserHandle owner, FeatureFlags flags,
+            ZonedDateTime time, String fileName, UserHandle owner,
             boolean allowOverwrite) throws ImageExportException {
         Trace.beginSection("ImageExporter_createEntry");
         try {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 31813b2..42499f0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -207,7 +207,7 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 813df11..859926c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -245,10 +245,6 @@
     /** */
     default void setNotificationPresenter(NotificationPresenter presenter) {}
 
-    /** */
-    default void setNotificationShadeWindowViewController(
-            NotificationShadeWindowViewController notificationShadeWindowViewController) {}
-
     /** Listens for shade visibility changes. */
     interface ShadeVisibilityListener {
         /** Called when shade expanded and visible state changed. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index 07836e4..b7a95e9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -65,6 +65,7 @@
     private final StatusBarWindowController mStatusBarWindowController;
     private final DeviceProvisionedController mDeviceProvisionedController;
 
+    private final Lazy<NotificationShadeWindowViewController> mNotifShadeWindowViewController;
     private final Lazy<NotificationPanelViewController> mNpvc;
     private final Lazy<AssistManager> mAssistManagerLazy;
     private final Lazy<NotificationGutsManager> mGutsManager;
@@ -72,7 +73,6 @@
     private boolean mExpandedVisible;
     private boolean mLockscreenOrShadeVisible;
 
-    private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
     private ShadeVisibilityListener mShadeVisibilityListener;
 
     @Inject
@@ -87,6 +87,7 @@
             DeviceProvisionedController deviceProvisionedController,
             NotificationShadeWindowController notificationShadeWindowController,
             @DisplayId int displayId,
+            Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewController,
             Lazy<NotificationPanelViewController> shadeViewControllerLazy,
             Lazy<AssistManager> assistManagerLazy,
             Lazy<NotificationGutsManager> gutsManager
@@ -105,6 +106,7 @@
         mDeviceProvisionedController = deviceProvisionedController;
         mGutsManager = gutsManager;
         mNotificationShadeWindowController = notificationShadeWindowController;
+        mNotifShadeWindowViewController = notificationShadeWindowViewController;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mDisplayId = displayId;
         mKeyguardStateController = keyguardStateController;
@@ -139,7 +141,7 @@
             // release focus immediately to kick off focus change transition
             mNotificationShadeWindowController.setNotificationShadeFocusable(false);
 
-            mNotificationShadeWindowViewController.cancelExpandHelper();
+            mNotifShadeWindowViewController.get().cancelExpandHelper();
             getNpvc().collapse(true, delayed, speedUpFactor);
         }
     }
@@ -242,7 +244,7 @@
     @Override
     public void cancelExpansionAndCollapseShade() {
         if (getNpvc().isTracking()) {
-            mNotificationShadeWindowViewController.cancelCurrentTouch();
+            mNotifShadeWindowViewController.get().cancelCurrentTouch();
         }
         if (getNpvc().isPanelExpanded()
                 && mStatusBarStateController.getState() == StatusBarState.SHADE) {
@@ -367,14 +369,8 @@
         mShadeVisibilityListener.expandedVisibleChanged(expandedVisible);
     }
 
-    @Override
-    public void setNotificationShadeWindowViewController(
-            NotificationShadeWindowViewController controller) {
-        mNotificationShadeWindowViewController = controller;
-    }
-
     private NotificationShadeWindowView getNotificationShadeWindowView() {
-        return mNotificationShadeWindowViewController.getView();
+        return mNotifShadeWindowViewController.get().getView();
     }
 
     private NotificationPanelViewController getNpvc() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 5d03a28..361226a4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -91,17 +91,14 @@
     }
 
     override fun instantCollapseShade() {
-        sceneInteractor.snapToScene(
-            SceneFamilies.Home,
-            "hide shade",
-        )
+        sceneInteractor.snapToScene(SceneFamilies.Home, "hide shade")
     }
 
     override fun animateCollapseShade(
         flags: Int,
         force: Boolean,
         delayed: Boolean,
-        speedUpFactor: Float
+        speedUpFactor: Float,
     ) {
         if (!force && !shadeInteractor.isAnyExpanded.value) {
             runPostCollapseActions()
@@ -147,7 +144,7 @@
         if (shadeInteractor.isAnyExpanded.value) {
             commandQueue.animateCollapsePanels(
                 CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
-                true /* force */
+                true, /* force */
             )
             assistManagerLazy.get().hideAssist()
         }
@@ -172,17 +169,11 @@
     }
 
     override fun expandToNotifications() {
-        sceneInteractor.changeScene(
-            SceneFamilies.NotifShade,
-            "ShadeController.animateExpandShade",
-        )
+        shadeInteractor.expandNotificationShade("ShadeController.animateExpandShade")
     }
 
     override fun expandToQs() {
-        sceneInteractor.changeScene(
-            SceneFamilies.QuickSettings,
-            "ShadeController.animateExpandQs",
-        )
+        shadeInteractor.expandQuickSettingsShade("ShadeController.animateExpandQs")
     }
 
     override fun setVisibilityListener(listener: ShadeVisibilityListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index c49cfbd..cb589aa 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -194,6 +194,7 @@
             if (qsVisible && field != value) {
                 header.alpha = ShadeInterpolation.getContentAlpha(value)
                 field = value
+                updateIgnoredSlots()
             }
         }
 
@@ -538,7 +539,7 @@
 
     private fun updateIgnoredSlots() {
         // switching from QQS to QS state halfway through the transition
-        if (singleCarrier || qsExpandedFraction < 0.5) {
+        if (singleCarrier || (!largeScreenActive && qsExpandedFraction < 0.5)) {
             iconContainer.removeIgnoredSlots(carrierIconSlots)
         } else {
             iconContainer.addIgnoredSlots(carrierIconSlots)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6fb96da..b046c50 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -140,6 +140,18 @@
      * animating.
      */
     val isUserInteractingWithQs: Flow<Boolean>
+
+    /**
+     * Triggers the expansion (opening) of the notification shade. If the notification shade is
+     * already open, this has no effect.
+     */
+    fun expandNotificationShade(loggingReason: String)
+
+    /**
+     * Triggers the expansion (opening) of the quick settings shade. If the quick settings shade is
+     * already open, this has no effect.
+     */
+    fun expandQuickSettingsShade(loggingReason: String)
 }
 
 fun createAnyExpansionFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index 6c0b55a..fb14828 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -49,4 +49,8 @@
     override val isShadeLayoutWide: StateFlow<Boolean> = inactiveFlowBoolean
 
     override fun getTopEdgeSplitFraction(): Float = 0.5f
+
+    override fun expandNotificationShade(loggingReason: String) {}
+
+    override fun expandQuickSettingsShade(loggingReason: String) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
index f48e31e..df09486 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
@@ -61,7 +61,7 @@
                 keyguardRepository.statusBarState,
                 repository.legacyShadeExpansion,
                 repository.qsExpansion,
-                sharedNotificationContainerInteractor.isSplitShadeEnabled
+                sharedNotificationContainerInteractor.isSplitShadeEnabled,
             ) {
                 lockscreenShadeExpansion,
                 statusBarState,
@@ -97,13 +97,13 @@
         repository.legacyExpandedOrAwaitingInputTransfer.stateIn(
             scope,
             SharingStarted.Eagerly,
-            false
+            false,
         )
 
     override val isUserInteractingWithShade: Flow<Boolean> =
         combine(
             userInteractingFlow(repository.legacyShadeTracking, repository.legacyShadeExpansion),
-            repository.legacyLockscreenShadeTracking
+            repository.legacyLockscreenShadeTracking,
         ) { legacyShadeTracking, legacyLockscreenShadeTracking ->
             legacyShadeTracking || legacyLockscreenShadeTracking
         }
@@ -111,6 +111,18 @@
     override val isUserInteractingWithQs: Flow<Boolean> =
         userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion)
 
+    override fun expandNotificationShade(loggingReason: String) {
+        throw UnsupportedOperationException(
+            "expandNotificationShade() is not supported in legacy shade"
+        )
+    }
+
+    override fun expandQuickSettingsShade(loggingReason: String) {
+        throw UnsupportedOperationException(
+            "expandQuickSettingsShade() is not supported in legacy shade"
+        )
+    }
+
     /**
      * Return a flow for whether a user is interacting with an expandable shade component using
      * tracking and expansion flows. NOTE: expansion must be a `StateFlow` to guarantee that
@@ -118,7 +130,7 @@
      */
     private fun userInteractingFlow(
         tracking: Flow<Boolean>,
-        expansion: StateFlow<Float>
+        expansion: StateFlow<Float>,
     ): Flow<Boolean> {
         return flow {
             // initial value is false
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 e84cfa5..81bf712 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
@@ -17,81 +17,70 @@
 package com.android.systemui.shade.domain.interactor
 
 import com.android.app.tracing.FlowTracing.traceAsCounter
+import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
 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.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.shared.model.ShadeMode
 import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
 /** ShadeInteractor implementation for Scene Container. */
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class ShadeInteractorSceneContainerImpl
 @Inject
 constructor(
     @Application scope: CoroutineScope,
-    sceneInteractor: SceneInteractor,
-    shadeRepository: ShadeRepository,
+    private val sceneInteractor: SceneInteractor,
+    private val shadeModeInteractor: ShadeModeInteractor,
 ) : BaseShadeInteractor {
     init {
         SceneContainerFlag.assertInNewMode()
     }
 
     override val shadeExpansion: StateFlow<Float> =
-        sceneBasedExpansion(sceneInteractor, SceneFamilies.NotifShade)
+        shadeModeInteractor.shadeMode
+            .flatMapLatest { shadeMode ->
+                transitionProgressExpansion(shadeMode.notificationsContentKey)
+            }
             .traceAsCounter("panel_expansion") { (it * 100f).toInt() }
             .stateIn(scope, SharingStarted.Eagerly, 0f)
 
-    private val sceneBasedQsExpansion =
-        sceneBasedExpansion(sceneInteractor, SceneFamilies.QuickSettings)
-
     override val qsExpansion: StateFlow<Float> =
-        combine(
-                shadeRepository.isShadeLayoutWide,
-                shadeExpansion,
-                sceneBasedQsExpansion,
-            ) { isSplitShadeEnabled, shadeExpansion, qsExpansion ->
-                if (isSplitShadeEnabled) {
-                    shadeExpansion
-                } else {
-                    qsExpansion
-                }
-            }
+        shadeModeInteractor.shadeMode
+            .flatMapLatest { shadeMode -> transitionProgressExpansion(shadeMode.qsContentKey) }
             .stateIn(scope, SharingStarted.Eagerly, 0f)
 
     override val isQsExpanded: StateFlow<Boolean> =
-        qsExpansion
-            .map { it > 0 }
-            .distinctUntilChanged()
-            .stateIn(scope, SharingStarted.Eagerly, false)
+        qsExpansion.map { it > 0 }.stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isQsBypassingShade: Flow<Boolean> =
-        combine(
-                sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
-                sceneInteractor.resolveSceneFamily(SceneFamilies.NotifShade),
-                ::Pair
-            )
-            .flatMapLatestConflated { (quickSettingsScene, notificationsScene) ->
+        shadeModeInteractor.shadeMode
+            .flatMapLatestConflated { shadeMode ->
                 sceneInteractor.transitionState
                     .map { state ->
                         when (state) {
                             is ObservableTransitionState.Idle -> false
                             is ObservableTransitionState.Transition ->
-                                state.toContent == quickSettingsScene &&
-                                    state.fromContent != notificationsScene
+                                state.toContent == shadeMode.qsContentKey &&
+                                    state.fromContent != shadeMode.notificationsContentKey
                         }
                     }
                     .distinctUntilChanged()
@@ -99,21 +88,22 @@
             .distinctUntilChanged()
 
     override val isQsFullscreen: Flow<Boolean> =
-        combine(
-                shadeRepository.isShadeLayoutWide,
-                sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
-                ::Pair
-            )
-            .flatMapLatestConflated { (isShadeLayoutWide, quickSettingsScene) ->
-                sceneInteractor.transitionState
-                    .map { state ->
-                        when (state) {
-                            is ObservableTransitionState.Idle ->
-                                !isShadeLayoutWide && state.currentScene == quickSettingsScene
-                            is ObservableTransitionState.Transition -> false
-                        }
-                    }
-                    .distinctUntilChanged()
+        shadeModeInteractor.shadeMode
+            .flatMapLatest { shadeMode ->
+                when (shadeMode) {
+                    ShadeMode.Single ->
+                        sceneInteractor.transitionState
+                            .map { state ->
+                                when (state) {
+                                    is ObservableTransitionState.Idle ->
+                                        state.currentScene == Scenes.QuickSettings
+                                    is ObservableTransitionState.Transition -> false
+                                }
+                            }
+                            .distinctUntilChanged()
+                    ShadeMode.Split,
+                    ShadeMode.Dual -> flowOf(false)
+                }
             }
             .distinctUntilChanged()
 
@@ -121,16 +111,79 @@
         createAnyExpansionFlow(scope, shadeExpansion, qsExpansion)
 
     override val isAnyExpanded =
-        anyExpansion
-            .map { it > 0f }
-            .distinctUntilChanged()
-            .stateIn(scope, SharingStarted.Eagerly, false)
+        anyExpansion.map { it > 0f }.stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isUserInteractingWithShade: Flow<Boolean> =
-        sceneBasedInteracting(sceneInteractor, SceneFamilies.NotifShade)
+        shadeModeInteractor.shadeMode.flatMapLatest { shadeMode ->
+            when (shadeMode) {
+                ShadeMode.Single,
+                ShadeMode.Split -> sceneBasedInteracting(sceneInteractor, Scenes.Shade)
+                ShadeMode.Dual ->
+                    overlayBasedInteracting(sceneInteractor, Overlays.NotificationsShade)
+            }
+        }
 
     override val isUserInteractingWithQs: Flow<Boolean> =
-        sceneBasedInteracting(sceneInteractor, SceneFamilies.QuickSettings)
+        shadeModeInteractor.shadeMode.flatMapLatest { shadeMode ->
+            when (shadeMode) {
+                ShadeMode.Single -> sceneBasedInteracting(sceneInteractor, Scenes.QuickSettings)
+                ShadeMode.Split -> sceneBasedInteracting(sceneInteractor, Scenes.Shade)
+                ShadeMode.Dual ->
+                    overlayBasedInteracting(sceneInteractor, Overlays.QuickSettingsShade)
+            }
+        }
+
+    override fun expandNotificationShade(loggingReason: String) {
+        if (shadeModeInteractor.isDualShade) {
+            if (Overlays.QuickSettingsShade in sceneInteractor.currentOverlays.value) {
+                sceneInteractor.replaceOverlay(
+                    from = Overlays.QuickSettingsShade,
+                    to = Overlays.NotificationsShade,
+                    loggingReason = loggingReason,
+                )
+            } else {
+                sceneInteractor.showOverlay(
+                    overlay = Overlays.NotificationsShade,
+                    loggingReason = loggingReason,
+                )
+            }
+        } else {
+            sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = loggingReason)
+        }
+    }
+
+    override fun expandQuickSettingsShade(loggingReason: String) {
+        if (shadeModeInteractor.isDualShade) {
+            if (Overlays.NotificationsShade in sceneInteractor.currentOverlays.value) {
+                sceneInteractor.replaceOverlay(
+                    from = Overlays.NotificationsShade,
+                    to = Overlays.QuickSettingsShade,
+                    loggingReason = loggingReason,
+                )
+            } else {
+                sceneInteractor.showOverlay(
+                    overlay = Overlays.QuickSettingsShade,
+                    loggingReason = loggingReason,
+                )
+            }
+        } else {
+            sceneInteractor.changeScene(
+                toScene = Scenes.QuickSettings,
+                loggingReason = loggingReason,
+            )
+        }
+    }
+
+    /**
+     * Returns a flow that uses scene transition progress to and from a content to a 0-1 expansion
+     * amount float.
+     */
+    private fun transitionProgressExpansion(contentKey: ContentKey): Flow<Float> {
+        return when (contentKey) {
+            is SceneKey -> sceneBasedExpansion(sceneInteractor, contentKey)
+            is OverlayKey -> overlayBasedExpansion(sceneInteractor, contentKey)
+        }
+    }
 
     /**
      * Returns a flow that uses scene transition progress to and from a scene that is pulled down
@@ -181,4 +234,60 @@
                 }
             }
             .distinctUntilChanged()
+
+    /**
+     * Returns a flow that uses scene transition progress to and from [overlay] to a 0-1 expansion
+     * amount float.
+     */
+    private fun overlayBasedExpansion(sceneInteractor: SceneInteractor, overlay: OverlayKey) =
+        sceneInteractor.transitionState
+            .flatMapLatestConflated { state ->
+                when (state) {
+                    is ObservableTransitionState.Idle ->
+                        flowOf(if (overlay in state.currentOverlays) 1f else 0f)
+                    is ObservableTransitionState.Transition ->
+                        if (state.toContent == overlay) {
+                            state.progress
+                        } else if (state.fromContent == overlay) {
+                            state.progress.map { progress -> 1 - progress }
+                        } else {
+                            flowOf(0f)
+                        }
+                }
+            }
+            .distinctUntilChanged()
+
+    /**
+     * Returns a flow that uses scene transition data to determine whether the user is interacting
+     * with [overlay].
+     */
+    private fun overlayBasedInteracting(sceneInteractor: SceneInteractor, overlay: OverlayKey) =
+        sceneInteractor.transitionState
+            .map { state ->
+                when (state) {
+                    is ObservableTransitionState.Idle -> false
+                    is ObservableTransitionState.Transition ->
+                        state.isInitiatedByUserInput &&
+                            (state.toContent == overlay || state.fromContent == overlay)
+                }
+            }
+            .distinctUntilChanged()
+
+    private val ShadeMode.notificationsContentKey: ContentKey
+        get() {
+            return when (this) {
+                ShadeMode.Single,
+                ShadeMode.Split -> Scenes.Shade
+                ShadeMode.Dual -> Overlays.NotificationsShade
+            }
+        }
+
+    private val ShadeMode.qsContentKey: ContentKey
+        get() {
+            return when (this) {
+                ShadeMode.Single -> Scenes.QuickSettings
+                ShadeMode.Split -> Scenes.Shade
+                ShadeMode.Dual -> Overlays.QuickSettingsShade
+            }
+        }
 }
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 e525b86..0fb3790 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
@@ -21,9 +21,10 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.shared.model.ShadeMode
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
@@ -45,10 +46,14 @@
     override val udfpsTransitionToFullShadeProgress =
         shadeRepository.udfpsTransitionToFullShadeProgress
 
+    @Deprecated("Use ShadeInteractor instead")
     override fun expandToNotifications() {
-        changeToShadeScene()
+        shadeInteractor.expandNotificationShade(
+            loggingReason = "ShadeLockscreenInteractorImpl.expandToNotifications"
+        )
     }
 
+    @Deprecated("Use ShadeInteractor instead")
     override val isExpanded
         get() = shadeInteractor.isAnyExpanded.value
 
@@ -60,15 +65,26 @@
         lockIconViewController.dozeTimeTick()
     }
 
+    @Deprecated("Not supported by scenes")
     override fun blockExpansionForCurrentTouch() {
         // TODO("b/324280998") Implement replacement or delete
     }
 
     override fun resetViews(animate: Boolean) {
+        val loggingReason = "ShadeLockscreenInteractorImpl.resetViews"
         // The existing comment to the only call to this claims it only calls it to collapse QS
-        changeToShadeScene()
+        if (shadeInteractor.shadeMode.value == ShadeMode.Dual) {
+            // TODO(b/356596436): Hide without animation if !animate.
+            sceneInteractor.hideOverlay(
+                overlay = Overlays.QuickSettingsShade,
+                loggingReason = loggingReason,
+            )
+        } else {
+            shadeInteractor.expandNotificationShade(loggingReason)
+        }
     }
 
+    @Deprecated("Not supported by scenes")
     override fun setPulsing(pulsing: Boolean) {
         // Now handled elsewhere. Do nothing.
     }
@@ -76,22 +92,30 @@
     override fun transitionToExpandedShade(delay: Long) {
         backgroundScope.launch {
             delay(delay)
-            withContext(mainDispatcher) { changeToShadeScene() }
+            withContext(mainDispatcher) {
+                shadeInteractor.expandNotificationShade(
+                    "ShadeLockscreenInteractorImpl.transitionToExpandedShade"
+                )
+            }
         }
     }
 
+    @Deprecated("Not supported by scenes")
     override fun resetViewGroupFade() {
         // Now handled elsewhere. Do nothing.
     }
 
+    @Deprecated("Not supported by scenes")
     override fun setKeyguardTransitionProgress(keyguardAlpha: Float, keyguardTranslationY: Int) {
         // Now handled elsewhere. Do nothing.
     }
 
+    @Deprecated("Not supported by scenes")
     override fun setOverStretchAmount(amount: Float) {
         // Now handled elsewhere. Do nothing.
     }
 
+    @Deprecated("TODO(b/325072511) delete this")
     override fun setKeyguardStatusBarAlpha(alpha: Float) {
         // TODO(b/325072511) delete this
     }
@@ -100,11 +124,4 @@
         sceneInteractor.changeScene(Scenes.Lockscreen, "showAodUi", sceneState = KeyguardState.AOD)
         // TODO(b/330311871) implement transition to AOD
     }
-
-    private fun changeToShadeScene() {
-        sceneInteractor.changeScene(
-            SceneFamilies.NotifShade,
-            "ShadeLockscreenInteractorImpl.expandToNotifications",
-        )
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
index 77ae679..caa4513 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt
@@ -51,6 +51,10 @@
      */
     val isShadeLayoutWide: StateFlow<Boolean>
 
+    /** Convenience shortcut for querying whether the current [shadeMode] is [ShadeMode.Dual]. */
+    val isDualShade: Boolean
+        get() = shadeMode.value is ShadeMode.Dual
+
     /**
      * The fraction between [0..1] (i.e., percentage) of screen width to consider the threshold
      * between "top-left" and "top-right" for the purposes of dual-shade invocation.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.java
index 0e7beb9d..02a29e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpManagerPhone.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.statusbar.phone;
+package com.android.systemui.statusbar.notification;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -47,6 +47,8 @@
 import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
+import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.AnimationStateHandler;
 import com.android.systemui.statusbar.policy.AvalancheController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpNotificationViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
similarity index 88%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpNotificationViewControllerEmptyImpl.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
index 9f76429..021d301 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpNotificationViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpNotificationViewControllerEmptyImpl.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone
+package com.android.systemui.statusbar.notification
 
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper.HeadsUpNotificationViewController
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNotificationViewController
 
 /** Empty impl of [HeadsUpNotificationViewController] for use with Scene Container */
 class HeadsUpNotificationViewControllerEmptyImpl : HeadsUpNotificationViewController {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
index 26bd7ac..0927a72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeadsUpTouchHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -11,10 +11,10 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.notification;
 
 import android.content.Context;
 import android.os.RemoteException;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
index 2b0d2aa..63c9e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationDataLayerModule.kt
@@ -16,7 +16,7 @@
 package com.android.systemui.statusbar.notification.data
 
 import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
 import dagger.Binds
 import dagger.Module
 
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 1214440a..7543f3b 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
@@ -120,7 +120,7 @@
 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape;
 import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index bcdc3bc..e5f63c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -129,9 +129,9 @@
 import com.android.systemui.statusbar.notification.shared.GroupHunAnimationFix;
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpNotificationViewControllerEmptyImpl;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper.HeadsUpNotificationViewController;
+import com.android.systemui.statusbar.notification.HeadsUpNotificationViewControllerEmptyImpl;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper.HeadsUpNotificationViewController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7227b93..50e9249 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1511,8 +1511,6 @@
         mNotificationShadeWindowController.fetchWindowRootView();
         getNotificationShadeWindowViewController().setupExpandedStatusBar();
         getNotificationShadeWindowViewController().setupCommunalHubLayout();
-        mShadeController.setNotificationShadeWindowViewController(
-                getNotificationShadeWindowViewController());
         mBackActionInteractor.setup(mQsController, mShadeSurface);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
index 0d0f2cd..7919c84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpModule.kt
@@ -1,6 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.systemui.statusbar.phone
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import dagger.Binds
 import dagger.Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index ca94363..c089092 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -31,7 +31,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.settingslib.bluetooth.BluetoothCallback;
-import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -72,7 +71,6 @@
     private final LocalBluetoothManager mLocalBluetoothManager;
     private final UserManager mUserManager;
     private final int mCurrentUser;
-    private final Context mContext;
     @GuardedBy("mConnectedDevices")
     private final List<CachedBluetoothDevice> mConnectedDevices = new ArrayList<>();
 
@@ -101,7 +99,6 @@
             @Main Looper mainLooper,
             @Nullable LocalBluetoothManager localBluetoothManager,
             @Nullable BluetoothAdapter bluetoothAdapter) {
-        mContext = context;
         mDumpManager = dumpManager;
         mLogger = logger;
         mBluetoothRepository = bluetoothRepository;
@@ -265,21 +262,9 @@
     }
 
     private Collection<CachedBluetoothDevice> getDevices() {
-        Collection<CachedBluetoothDevice> devices =
-                mLocalBluetoothManager != null
-                        ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
-                        : Collections.emptyList();
-        if (com.android.settingslib.flags.Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            // When the device is exclusively managed by its owner app it needs to be hidden.
-            devices =
-                    devices.stream()
-                            .filter(
-                                    device ->
-                                            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
-                                                    mContext, device.getDevice()))
-                            .toList();
-        }
-        return devices;
+        return mLocalBluetoothManager != null
+                ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
+                : Collections.emptyList();
     }
 
     private void updateConnected() {
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
index a3b1867..411ff8b 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
@@ -24,8 +24,6 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
 import com.android.systemui.res.R
 import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureMonitor
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
-import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
 
 @Composable
 fun BackGestureTutorialScreen(
@@ -49,14 +47,11 @@
                 )
         )
     val gestureMonitorProvider =
-        object : GestureMonitorProvider {
-            override fun createGestureMonitor(
-                gestureDistanceThresholdPx: Int,
-                gestureStateChangedCallback: (GestureState) -> Unit
-            ): TouchpadGestureMonitor {
-                return BackGestureMonitor(gestureDistanceThresholdPx, gestureStateChangedCallback)
+        DistanceBasedGestureMonitorProvider(
+            monitorFactory = { distanceThresholdPx, gestureStateCallback ->
+                BackGestureMonitor(distanceThresholdPx, gestureStateCallback)
             }
-        }
+        )
     GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
index 57d7c84..0ecbf70 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.touchpad.tutorial.ui.composable
 
+import android.content.res.Resources
 import androidx.activity.compose.BackHandler
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
@@ -39,12 +40,35 @@
 import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
 
 interface GestureMonitorProvider {
-    fun createGestureMonitor(
-        gestureDistanceThresholdPx: Int,
+
+    @Composable
+    fun rememberGestureMonitor(
+        resources: Resources,
         gestureStateChangedCallback: (GestureState) -> Unit
     ): TouchpadGestureMonitor
 }
 
+typealias gestureStateCallback = (GestureState) -> Unit
+
+class DistanceBasedGestureMonitorProvider(
+    val monitorFactory: (Int, gestureStateCallback) -> TouchpadGestureMonitor
+) : GestureMonitorProvider {
+
+    @Composable
+    override fun rememberGestureMonitor(
+        resources: Resources,
+        gestureStateChangedCallback: (GestureState) -> Unit
+    ): TouchpadGestureMonitor {
+        val distanceThresholdPx =
+            resources.getDimensionPixelSize(
+                com.android.internal.R.dimen.system_gestures_distance_threshold
+            )
+        return remember(distanceThresholdPx) {
+            monitorFactory(distanceThresholdPx, gestureStateChangedCallback)
+        }
+    }
+}
+
 fun GestureState.toTutorialActionState(): TutorialActionState {
     return when (this) {
         NOT_STARTED -> TutorialActionState.NOT_STARTED
@@ -62,19 +86,12 @@
 ) {
     BackHandler(onBack = onBack)
     var gestureState by remember { mutableStateOf(NOT_STARTED) }
-    val swipeDistanceThresholdPx =
-        LocalContext.current.resources.getDimensionPixelSize(
-            com.android.internal.R.dimen.system_gestures_distance_threshold
+    val gestureMonitor =
+        gestureMonitorProvider.rememberGestureMonitor(
+            resources = LocalContext.current.resources,
+            gestureStateChangedCallback = { gestureState = it }
         )
-    val gestureHandler =
-        remember(swipeDistanceThresholdPx) {
-            TouchpadGestureHandler(
-                gestureMonitorProvider.createGestureMonitor(
-                    swipeDistanceThresholdPx,
-                    gestureStateChangedCallback = { gestureState = it }
-                )
-            )
-        }
+    val gestureHandler = remember(gestureMonitor) { TouchpadGestureHandler(gestureMonitor) }
     TouchpadGesturesHandlingBox(gestureHandler, gestureState) {
         ActionTutorialContent(
             gestureState.toTutorialActionState(),
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
index d4eb0cd..f2fec5f 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
@@ -23,9 +23,7 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
 import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
 import com.android.systemui.res.R
-import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
 import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureMonitor
-import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
 
 @Composable
 fun HomeGestureTutorialScreen(
@@ -49,14 +47,11 @@
                 )
         )
     val gestureMonitorProvider =
-        object : GestureMonitorProvider {
-            override fun createGestureMonitor(
-                gestureDistanceThresholdPx: Int,
-                gestureStateChangedCallback: (GestureState) -> Unit
-            ): TouchpadGestureMonitor {
-                return HomeGestureMonitor(gestureDistanceThresholdPx, gestureStateChangedCallback)
+        DistanceBasedGestureMonitorProvider(
+            monitorFactory = { distanceThresholdPx, gestureStateCallback ->
+                HomeGestureMonitor(distanceThresholdPx, gestureStateCallback)
             }
-        }
+        )
     GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
new file mode 100644
index 0000000..b2fb6cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/RecentAppsGestureTutorialScreen.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui.composable
+
+import android.content.res.Resources
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import com.airbnb.lottie.compose.rememberLottieDynamicProperties
+import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
+import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
+import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
+import com.android.systemui.touchpad.tutorial.ui.gesture.RecentAppsGestureMonitor
+import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureMonitor
+
+@Composable
+fun RecentAppsGestureTutorialScreen(
+    onDoneButtonClicked: () -> Unit,
+    onBack: () -> Unit,
+) {
+    val screenConfig =
+        TutorialScreenConfig(
+            colors = rememberScreenColors(),
+            strings =
+                TutorialScreenConfig.Strings(
+                    titleResId = R.string.touchpad_recent_apps_gesture_action_title,
+                    bodyResId = R.string.touchpad_recent_apps_gesture_guidance,
+                    titleSuccessResId = R.string.touchpad_recent_apps_gesture_success_title,
+                    bodySuccessResId = R.string.touchpad_recent_apps_gesture_success_body
+                ),
+            animations =
+                TutorialScreenConfig.Animations(
+                    educationResId = R.raw.trackpad_recent_apps_edu,
+                    successResId = R.raw.trackpad_recent_apps_success
+                )
+        )
+    val gestureMonitorProvider =
+        object : GestureMonitorProvider {
+            @Composable
+            override fun rememberGestureMonitor(
+                resources: Resources,
+                gestureStateChangedCallback: (GestureState) -> Unit
+            ): TouchpadGestureMonitor {
+                val distanceThresholdPx =
+                    resources.getDimensionPixelSize(
+                        com.android.internal.R.dimen.system_gestures_distance_threshold
+                    )
+                val velocityThresholdPxPerMs =
+                    resources.getDimension(R.dimen.touchpad_recent_apps_gesture_velocity_threshold)
+                return remember(distanceThresholdPx, velocityThresholdPxPerMs) {
+                    RecentAppsGestureMonitor(
+                        distanceThresholdPx,
+                        gestureStateChangedCallback,
+                        velocityThresholdPxPerMs
+                    )
+                }
+            }
+        }
+    GestureTutorialScreen(screenConfig, gestureMonitorProvider, onDoneButtonClicked, onBack)
+}
+
+@Composable
+private fun rememberScreenColors(): TutorialScreenConfig.Colors {
+    val secondaryFixedDim = LocalAndroidColorScheme.current.secondaryFixedDim
+    val onSecondaryFixed = LocalAndroidColorScheme.current.onSecondaryFixed
+    val onSecondaryFixedVariant = LocalAndroidColorScheme.current.onSecondaryFixedVariant
+    val dynamicProperties =
+        rememberLottieDynamicProperties(
+            rememberColorFilterProperty(".secondaryFixedDim", secondaryFixedDim),
+            rememberColorFilterProperty(".onSecondaryFixed", onSecondaryFixed),
+            rememberColorFilterProperty(".onSecondaryFixedVariant", onSecondaryFixedVariant)
+        )
+    val screenColors =
+        remember(dynamicProperties) {
+            TutorialScreenConfig.Colors(
+                background = onSecondaryFixed,
+                title = secondaryFixedDim,
+                animationColors = dynamicProperties,
+            )
+        }
+    return screenColors
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 65b452a..5a77c04 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -41,7 +41,7 @@
 fun TutorialSelectionScreen(
     onBackTutorialClicked: () -> Unit,
     onHomeTutorialClicked: () -> Unit,
-    onActionKeyTutorialClicked: () -> Unit,
+    onRecentAppsTutorialClicked: () -> Unit,
     onDoneButtonClicked: () -> Unit,
 ) {
     Column(
@@ -55,7 +55,7 @@
         TutorialSelectionButtons(
             onBackTutorialClicked = onBackTutorialClicked,
             onHomeTutorialClicked = onHomeTutorialClicked,
-            onActionKeyTutorialClicked = onActionKeyTutorialClicked,
+            onRecentAppsTutorialClicked = onRecentAppsTutorialClicked,
             modifier = Modifier.padding(60.dp)
         )
         DoneButton(
@@ -69,7 +69,7 @@
 private fun TutorialSelectionButtons(
     onBackTutorialClicked: () -> Unit,
     onHomeTutorialClicked: () -> Unit,
-    onActionKeyTutorialClicked: () -> Unit,
+    onRecentAppsTutorialClicked: () -> Unit,
     modifier: Modifier = Modifier
 ) {
     Row(
@@ -90,8 +90,8 @@
             modifier = Modifier.weight(1f)
         )
         TutorialButton(
-            text = stringResource(R.string.touchpad_tutorial_action_key_button),
-            onClick = onActionKeyTutorialClicked,
+            text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button),
+            onClick = onRecentAppsTutorialClicked,
             color = MaterialTheme.colorScheme.tertiary,
             modifier = Modifier.weight(1f)
         )
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 821b51a..46ea352 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -32,10 +32,12 @@
 import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
 import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
 import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
+import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen
 import com.android.systemui.touchpad.tutorial.ui.composable.TutorialSelectionScreen
 import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.ACTION_KEY
 import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.BACK_GESTURE
 import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.HOME_GESTURE
+import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.RECENT_APPS_GESTURE
 import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.TUTORIAL_SELECTION
 import com.android.systemui.touchpad.tutorial.ui.viewmodel.TouchpadTutorialViewModel
 import javax.inject.Inject
@@ -84,7 +86,7 @@
             TutorialSelectionScreen(
                 onBackTutorialClicked = { vm.goTo(BACK_GESTURE) },
                 onHomeTutorialClicked = { vm.goTo(HOME_GESTURE) },
-                onActionKeyTutorialClicked = { vm.goTo(ACTION_KEY) },
+                onRecentAppsTutorialClicked = { vm.goTo(RECENT_APPS_GESTURE) },
                 onDoneButtonClicked = closeTutorial
             )
         BACK_GESTURE ->
@@ -97,6 +99,11 @@
                 onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
                 onBack = { vm.goTo(TUTORIAL_SELECTION) },
             )
+        RECENT_APPS_GESTURE ->
+            RecentAppsGestureTutorialScreen(
+                onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
+                onBack = { vm.goTo(TUTORIAL_SELECTION) },
+            )
         ACTION_KEY -> // TODO(b/358105049) move action key tutorial to OOBE flow
         ActionKeyTutorialScreen(
                 onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
index 43266ad..599e1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
@@ -64,5 +64,6 @@
     TUTORIAL_SELECTION,
     BACK_GESTURE,
     HOME_GESTURE,
+    RECENT_APPS_GESTURE,
     ACTION_KEY,
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 030a20a..079c72f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -539,10 +539,12 @@
                                     != 0;
             changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
         } else if (stream == AudioManager.STREAM_VOICE_CALL) {
-            final boolean routedToBluetooth =
-                    (mAudio.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)
-                            & AudioManager.DEVICE_OUT_BLE_HEADSET) != 0;
-            changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
+            final int devices = mAudio.getDevicesForStream(AudioManager.STREAM_VOICE_CALL);
+            final int bluetoothDevicesMask = (AudioManager.DEVICE_OUT_BLE_HEADSET
+                    | AudioManager.DEVICE_OUT_BLUETOOTH_SCO_HEADSET
+                    | AudioManager.DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+            changed |= updateStreamRoutedToBluetoothW(stream,
+                    (devices & bluetoothDevicesMask) != 0);
         }
         return changed;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7786453..db4f9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1991,7 +1991,7 @@
                                             : R.drawable.ic_volume_media_bt;
             }
         } else if (isStreamMuted(ss)) {
-            iconRes = (ss.muted && isTv()) ? R.drawable.ic_volume_media_off : row.iconMuteRes;
+            iconRes = row.iconMuteRes;
         } else {
             iconRes = mShowLowMediaVolumeIcon && ss.level * 2 < (ss.levelMax + ss.levelMin)
                       ? R.drawable.ic_volume_media_low : row.iconRes;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index c0d8be3..4bb01ec 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -43,6 +43,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.flags.FakeFeatureFlags;
@@ -96,6 +97,8 @@
     private UserActivityNotifier mUserActivityNotifier;
     private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController;
     private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this);
+    private final BouncerHapticPlayer mBouncerHapticPlayer =
+            mKosmosJavaAdapter.getBouncerHapticHelper();
     private final FakeMSDLPlayer mMSDLPlayer = mKosmosJavaAdapter.getMsdlPlayer();
 
     @Before
@@ -119,8 +122,8 @@
         return new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
                 mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
                 mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector,
-                mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor, mMSDLPlayer,
-                mUserActivityNotifier) {
+                mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor,
+                mBouncerHapticPlayer, mUserActivityNotifier) {
             @Override
             void resetState() {
             }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 873bc2c..2c1dacd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -35,11 +35,13 @@
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
 import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
+import com.android.systemui.testKosmos
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
@@ -107,6 +109,8 @@
 
     @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
 
+    private val kosmos = testKosmos()
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
@@ -151,8 +155,8 @@
             mSelectedUserInteractor,
             uiEventLogger,
             keyguardKeyboardInteractor,
-            null,
-            mUserActivityNotifier
+            kosmos.bouncerHapticPlayer,
+            mUserActivityNotifier,
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index f141a49..9cd5215 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -28,8 +28,10 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
 import com.android.systemui.res.R
+import com.android.systemui.testKosmos
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
@@ -73,6 +75,8 @@
     private val updateMonitorCallbackArgumentCaptor =
         ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
 
+    private val kosmos = testKosmos()
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
@@ -103,8 +107,8 @@
                 fakeFeatureFlags,
                 mSelectedUserInteractor,
                 keyguardKeyboardInteractor,
-                null,
-                mUserActivityNotifier
+                kosmos.bouncerHapticPlayer,
+                mUserActivityNotifier,
             )
         underTest.init()
         underTest.onViewAttached()
@@ -162,14 +166,14 @@
         updateMonitorCallbackArgumentCaptor.value.onSimStateChanged(
             /* subId= */ 0,
             /* slotId= */ 0,
-            TelephonyManager.SIM_STATE_PIN_REQUIRED
+            TelephonyManager.SIM_STATE_PIN_REQUIRED,
         )
         verify(keyguardSecurityCallback, never()).showCurrentSecurityScreen()
 
         updateMonitorCallbackArgumentCaptor.value.onSimStateChanged(
             /* subId= */ 0,
             /* slotId= */ 0,
-            TelephonyManager.SIM_STATE_PUK_REQUIRED
+            TelephonyManager.SIM_STATE_PUK_REQUIRED,
         )
 
         verify(keyguardSecurityCallback).showCurrentSecurityScreen()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index a03c839..3c22997 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -29,8 +29,10 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
 import com.android.systemui.res.R
+import com.android.systemui.testKosmos
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.util.mockito.any
 import org.junit.Before
@@ -65,6 +67,8 @@
         KeyguardMessageAreaController<BouncerKeyguardMessageArea>
     @Mock private lateinit var mUserActivityNotifier: UserActivityNotifier
 
+    private val kosmos = testKosmos()
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
@@ -98,8 +102,8 @@
                 fakeFeatureFlags,
                 mSelectedUserInteractor,
                 keyguardKeyboardInteractor,
-                null,
-                mUserActivityNotifier
+                kosmos.bouncerHapticPlayer,
+                mUserActivityNotifier,
             )
         underTest.init()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 76539d7..633efd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -63,21 +63,27 @@
     private val defaultDisplay =
         display(type = TYPE_INTERNAL, id = DEFAULT_DISPLAY, state = Display.STATE_ON)
 
-    private lateinit var displayRepository: DisplayRepositoryImpl
+    // This is Lazy as displays could be set before the instance is created, and we want to verify
+    // that the initial state (soon after construction) contains the expected ones set in every
+    // test.
+    private val displayRepository: DisplayRepositoryImpl by lazy {
+        DisplayRepositoryImpl(
+                displayManager,
+                testHandler,
+                TestScope(UnconfinedTestDispatcher()),
+                UnconfinedTestDispatcher(),
+            )
+            .also {
+                verify(displayManager, never()).registerDisplayListener(any(), any())
+                // It needs to be called, just once, for the initial value.
+                verify(displayManager).getDisplays()
+            }
+    }
 
     @Before
     fun setup() {
         setDisplays(listOf(defaultDisplay))
         setAllDisplaysIncludingDisabled(DEFAULT_DISPLAY)
-        displayRepository =
-            DisplayRepositoryImpl(
-                displayManager,
-                testHandler,
-                TestScope(UnconfinedTestDispatcher()),
-                UnconfinedTestDispatcher()
-            )
-        verify(displayManager, never()).registerDisplayListener(any(), any())
-        verify(displayManager, never()).getDisplays(any())
     }
 
     @Test
@@ -502,7 +508,7 @@
             .registerDisplayListener(
                 connectedDisplayListener.capture(),
                 eq(testHandler),
-                eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
+                eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED),
             )
         return flowValue
     }
@@ -522,7 +528,7 @@
                     DisplayManager.EVENT_FLAG_DISPLAY_ADDED or
                         DisplayManager.EVENT_FLAG_DISPLAY_CHANGED or
                         DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
-                )
+                ),
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index b02cccc..4959224 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -146,9 +146,7 @@
         whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt()))
             .thenReturn(mock(ResolveInfo::class.java))
 
-        mSetFlagsRule.disableFlags(
-            com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
-        )
+        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
 
         subject = createOverviewProxyService(context)
     }
@@ -283,6 +281,7 @@
             statusBarWinController,
             sysUiState,
             mock(),
+            mock(),
             userTracker,
             userManager,
             wakefulnessLifecycle,
@@ -294,7 +293,7 @@
             dumpManager,
             unfoldTransitionProgressForwarder,
             broadcastDispatcher,
-            keyboardTouchpadEduStatsInteractor
+            keyboardTouchpadEduStatsInteractor,
         )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
index f4d7a5b..d58b68b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -47,7 +47,6 @@
 import androidx.test.filters.MediumTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FakeFeatureFlags;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -79,7 +78,6 @@
     private static final ZonedDateTime CAPTURE_TIME =
             ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("America/New_York"));
 
-    private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
     @Mock
     private ContentResolver mMockContentResolver;
 
@@ -125,7 +123,7 @@
     @Test
     public void testImageExport() throws ExecutionException, InterruptedException, IOException {
         ContentResolver contentResolver = mContext.getContentResolver();
-        ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
+        ImageExporter exporter = new ImageExporter(contentResolver);
 
         UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
         Bitmap original = createCheckerBitmap(10, 10, 10);
@@ -191,7 +189,7 @@
         // metadata are not affected by the specified file name.
         final String customizedFileName = "customized_file_name";
         ContentResolver contentResolver = mContext.getContentResolver();
-        ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
+        ImageExporter exporter = new ImageExporter(contentResolver);
 
         UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
         Bitmap original = createCheckerBitmap(10, 10, 10);
@@ -228,7 +226,7 @@
 
     @Test
     public void testSetUser() {
-        ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
+        ImageExporter exporter = new ImageExporter(mMockContentResolver);
 
         UserHandle imageUserHande = UserHandle.of(10);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
index 886b32b..717f82d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
@@ -31,12 +31,10 @@
 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -74,7 +72,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -98,6 +95,10 @@
     private static final String BACKLINKS_TASK_APP_NAME = "Ultimate question app";
     private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
     private static final AssistContent EMPTY_ASSIST_CONTENT = new AssistContent();
+    private static final ResolveInfo BACKLINKS_TASK_RESOLVE_INFO =
+            createBacklinksTaskResolveInfo();
+    private static final RunningTaskInfo BACKLINKS_TASK_RUNNING_TASK_INFO =
+            createTaskInfoForBacklinksTask();
 
     @Mock
     private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
@@ -111,26 +112,11 @@
     Context mMockedContext;
     @Mock
     private PackageManager mPackageManager;
-    private ArgumentCaptor<Intent> mPackageManagerLauncherIntentCaptor;
-    private ArgumentCaptor<Intent> mPackageManagerBacklinkIntentCaptor;
     private AppClipsViewModel mViewModel;
 
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
-        mPackageManagerLauncherIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-        mPackageManagerBacklinkIntentCaptor = ArgumentCaptor.forClass(Intent.class);
-
-        // Set up mocking for backlinks.
-        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
-                .thenReturn(List.of(createTaskInfoForBacklinksTask()));
-        ResolveInfo expectedResolveInfo = createBacklinksTaskResolveInfo();
-        when(mPackageManager.resolveActivity(mPackageManagerLauncherIntentCaptor.capture(),
-                anyInt())).thenReturn(expectedResolveInfo);
-        when(mPackageManager.queryIntentActivities(mPackageManagerBacklinkIntentCaptor.capture(),
-                eq(MATCH_DEFAULT_ONLY))).thenReturn(List.of(expectedResolveInfo));
-        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
-        when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);
 
         mViewModel = new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, mImageExporter,
                 mAtmService, mAssistContentRequester, mMockedContext,
@@ -208,19 +194,18 @@
     }
 
     @Test
-    public void triggerBacklinks_shouldUpdateBacklinks_withUri() {
+    public void triggerBacklinks_shouldUpdateBacklinks_withUri() throws RemoteException {
         Uri expectedUri = Uri.parse("https://developers.android.com");
         AssistContent contentWithUri = new AssistContent();
         contentWithUri.setWebUri(expectedUri);
         mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
+        mockPackageManagerToResolveUri(expectedUri, BACKLINKS_TASK_RESOLVE_INFO);
+        mockBacklinksTaskForMainLauncherIntent();
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
 
-        Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
-        assertThat(queriedIntent.getData()).isEqualTo(expectedUri);
-        assertThat(queriedIntent.getAction()).isEqualTo(ACTION_VIEW);
-
         BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
         assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
         ClipData clipData = result.getClipData();
@@ -234,14 +219,17 @@
     }
 
     @Test
-    public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp() {
+    public void triggerBacklinks_shouldUpdateBacklinks_withUriForDifferentApp()
+            throws RemoteException {
+        // Mock for the screenshotted app so that it can be used for fallback backlink.
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
+        mockBacklinksTaskForMainLauncherIntent();
+
         Uri expectedUri = Uri.parse("https://android.com");
         AssistContent contentWithUri = new AssistContent();
         contentWithUri.setWebUri(expectedUri);
         mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
 
-        // Reset PackageManager mocking done in setup.
-        reset(mPackageManager);
         String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
         String appName2 = BACKLINKS_TASK_APP_NAME + 2;
         ResolveInfo resolveInfo2 = createBacklinksTaskResolveInfo();
@@ -250,14 +238,9 @@
         activityInfo2.packageName = package2;
         activityInfo2.applicationInfo.packageName = package2;
 
-        Intent app2LauncherIntent = new Intent(ACTION_MAIN).addCategory(
-                CATEGORY_LAUNCHER).setPackage(package2);
-        when(mPackageManager.resolveActivity(intentEquals(app2LauncherIntent), eq(/* flags= */ 0)))
-                .thenReturn(resolveInfo2);
-        Intent uriIntent = new Intent(ACTION_VIEW).setData(expectedUri);
-        when(mPackageManager.queryIntentActivities(intentEquals(uriIntent), eq(MATCH_DEFAULT_ONLY)))
-                .thenReturn(List.of(resolveInfo2));
-        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
+        // Mock the different app resolve info so that backlinks resolves to this different app.
+        mockPackageManagerToResolveUri(expectedUri, resolveInfo2);
+        mockPmToResolveForMainLauncherIntent(resolveInfo2);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
@@ -273,30 +256,15 @@
         assertThat(mViewModel.getBacklinksLiveData().getValue().size()).isEqualTo(1);
     }
 
-    private static class IntentMatcher implements ArgumentMatcher<Intent> {
-        private final Intent mExpectedIntent;
-
-        IntentMatcher(Intent expectedIntent) {
-            mExpectedIntent = expectedIntent;
-        }
-
-        @Override
-        public boolean matches(Intent actualIntent) {
-            return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
-        }
-    }
-
-    private static Intent intentEquals(Intent intent) {
-        return argThat(new IntentMatcher(intent));
-    }
-
     @Test
-    public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent() {
+    public void triggerBacklinks_withNonResolvableUri_usesMainLauncherIntent()
+            throws RemoteException {
         Uri expectedUri = Uri.parse("https://developers.android.com");
         AssistContent contentWithUri = new AssistContent();
         contentWithUri.setWebUri(expectedUri);
         mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
-        resetPackageManagerMockingForUsingFallbackBacklinks();
+        mockBacklinksTaskForMainLauncherIntent();
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
@@ -305,18 +273,19 @@
     }
 
     @Test
-    public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent() {
+    public void triggerBacklinks_shouldUpdateBacklinks_withAppProvidedIntent()
+            throws RemoteException {
         Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
         AssistContent contentWithAppProvidedIntent = new AssistContent();
         contentWithAppProvidedIntent.setIntent(expectedIntent);
         mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
+        mockQueryIntentActivities(expectedIntent, BACKLINKS_TASK_RESOLVE_INFO);
+        mockBacklinksTaskForMainLauncherIntent();
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
 
-        Intent queriedIntent = mPackageManagerBacklinkIntentCaptor.getValue();
-        assertThat(queriedIntent.getPackage()).isEqualTo(expectedIntent.getPackage());
-
         BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
         assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
         ClipData clipData = result.getClipData();
@@ -328,12 +297,14 @@
     }
 
     @Test
-    public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent() {
+    public void triggerBacklinks_withNonResolvableAppProvidedIntent_usesMainLauncherIntent()
+            throws RemoteException {
         Intent expectedIntent = new Intent().setPackage(BACKLINKS_TASK_PACKAGE_NAME);
         AssistContent contentWithAppProvidedIntent = new AssistContent();
         contentWithAppProvidedIntent.setIntent(expectedIntent);
         mockForAssistContent(contentWithAppProvidedIntent, BACKLINKS_TASK_ID);
-        resetPackageManagerMockingForUsingFallbackBacklinks();
+        mockBacklinksTaskForMainLauncherIntent();
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
@@ -342,25 +313,28 @@
     }
 
     @Test
-    public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent() {
+    public void triggerBacklinks_shouldUpdateBacklinks_withMainLauncherIntent()
+            throws RemoteException {
         mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+        mockBacklinksTaskForMainLauncherIntent();
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
 
-        Intent queriedIntent = mPackageManagerLauncherIntentCaptor.getValue();
-        assertThat(queriedIntent.getPackage()).isEqualTo(BACKLINKS_TASK_PACKAGE_NAME);
-        assertThat(queriedIntent.getAction()).isEqualTo(ACTION_MAIN);
-        assertThat(queriedIntent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
-
         verifyMainLauncherBacklinksIntent();
     }
 
     @Test
-    public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable() {
-        reset(mPackageManager);
+    public void triggerBacklinks_withNonResolvableMainLauncherIntent_noBacklinksAvailable()
+            throws RemoteException {
         mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
 
+        // Mock ATM service so we return task info but don't mock PM to resolve the task intent.
+        when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+                false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
+                List.of(BACKLINKS_TASK_RUNNING_TASK_INFO));
+
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
 
@@ -371,11 +345,9 @@
     @Test
     public void triggerBacklinks_nonStandardActivityIgnored_noBacklinkAvailable()
             throws RemoteException {
-        reset(mAtmService);
         RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
         taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
-        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
-                .thenReturn(List.of(taskInfo));
+        mockAtmToReturnRunningTaskInfo(taskInfo);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
@@ -399,9 +371,9 @@
     public void triggerBacklinks_multipleAppsOnScreen_multipleBacklinksAvailable()
             throws RemoteException {
         // Set up mocking for multiple backlinks.
-        reset(mAtmService, mPackageManager);
-        RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
         ResolveInfo resolveInfo1 = createBacklinksTaskResolveInfo();
+        RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
+        runningTaskInfo1.topActivityInfo = resolveInfo1.activityInfo;
 
         int taskId2 = BACKLINKS_TASK_ID + 2;
         String package2 = BACKLINKS_TASK_PACKAGE_NAME + 2;
@@ -418,27 +390,23 @@
         runningTaskInfo2.topActivityInfo = resolveInfo2.activityInfo;
         runningTaskInfo2.baseIntent = new Intent().setComponent(runningTaskInfo2.topActivity);
 
-        // For each task, the logic queries PM 3 times, twice for verifying if an app can be
-        // launched via launcher and once with the data provided in backlink intent.
-        when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo1,
-                resolveInfo1, resolveInfo2, resolveInfo2);
-        when(mPackageManager.queryIntentActivities(any(Intent.class), eq(MATCH_DEFAULT_ONLY)))
-                .thenReturn(List.of(resolveInfo1)).thenReturn(List.of(resolveInfo2));
-        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
-        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
-                .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+        mockAtmToReturnRunningTaskInfo(runningTaskInfo1, runningTaskInfo2);
+        mockPmToResolveForMainLauncherIntent(resolveInfo1);
+        mockPmToResolveForMainLauncherIntent(resolveInfo2);
 
         // Using app provided web uri for the first backlink.
         Uri expectedUri = Uri.parse("https://developers.android.com");
         AssistContent contentWithUri = new AssistContent();
         contentWithUri.setWebUri(expectedUri);
         mockForAssistContent(contentWithUri, BACKLINKS_TASK_ID);
+        mockPackageManagerToResolveUri(expectedUri, resolveInfo1);
 
         // Using app provided intent for the second backlink.
         Intent expectedIntent = new Intent().setPackage(package2);
         AssistContent contentWithAppProvidedIntent = new AssistContent();
         contentWithAppProvidedIntent.setIntent(expectedIntent);
         mockForAssistContent(contentWithAppProvidedIntent, taskId2);
+        mockQueryIntentActivities(expectedIntent, resolveInfo2);
 
         // Set up complete, trigger the backlinks action.
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -460,11 +428,12 @@
     @Test
     public void triggerBacklinks_singleCrossProfileApp_shouldIndicateError()
             throws RemoteException {
-        reset(mAtmService);
         RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
         taskInfo.userId = UserHandle.myUserId() + 1;
-        when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
-                .thenReturn(List.of(taskInfo));
+        when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+                false, /* keepIntentExtra */ false, DEFAULT_DISPLAY)).thenReturn(List.of(taskInfo));
+        when(mPackageManager.loadItemIcon(taskInfo.topActivityInfo,
+                taskInfo.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
 
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
         waitForIdleSync();
@@ -478,13 +447,13 @@
             throws RemoteException {
         // Set up mocking for multiple backlinks.
         mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
-        reset(mAtmService);
-        RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
         RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
         runningTaskInfo2.userId = UserHandle.myUserId() + 1;
 
-        when(mAtmService.getTasks(anyInt(), anyBoolean(), anyBoolean(), anyInt()))
-                .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+        mockAtmToReturnRunningTaskInfo(BACKLINKS_TASK_RUNNING_TASK_INFO, runningTaskInfo2);
+        when(mPackageManager.loadItemIcon(runningTaskInfo2.topActivityInfo,
+                runningTaskInfo2.topActivityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
+        mockBacklinksTaskForMainLauncherIntent();
 
         // Set up complete, trigger the backlinks action.
         mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
@@ -497,22 +466,6 @@
         assertThat(actualBacklinks.get(1)).isInstanceOf(CrossProfileError.class);
     }
 
-    private void resetPackageManagerMockingForUsingFallbackBacklinks() {
-        ResolveInfo backlinksTaskResolveInfo = createBacklinksTaskResolveInfo();
-        reset(mPackageManager);
-        when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
-        when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
-                // Firstly, the logic queries whether a package has a launcher activity, this should
-                // resolve otherwise the logic filters out the task.
-                .thenReturn(backlinksTaskResolveInfo)
-                // Secondly, the logic builds a fallback main launcher intent, this should also
-                // resolve for the fallback intent to build correctly.
-                .thenReturn(backlinksTaskResolveInfo)
-                // Lastly, logic queries with the backlinks intent, this should not resolve for the
-                // logic to use the fallback intent.
-                .thenReturn(null);
-    }
-
     private void verifyMainLauncherBacklinksIntent() {
         BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
         assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
@@ -540,6 +493,59 @@
         }).when(mAssistContentRequester).requestAssistContent(eq(taskId), any());
     }
 
+    private void mockPackageManagerToResolveUri(Uri uriToResolve, ResolveInfo resolveInfoToReturn) {
+        Intent uriIntent = new Intent(ACTION_VIEW).setData(uriToResolve);
+        mockQueryIntentActivities(uriIntent, resolveInfoToReturn);
+        mockPmToLoadAppIcon(resolveInfoToReturn);
+    }
+
+    private void mockQueryIntentActivities(Intent expectedIntent, ResolveInfo resolveInfoToReturn) {
+        when(mPackageManager.queryIntentActivities(intentEquals(expectedIntent),
+                eq(MATCH_DEFAULT_ONLY)))
+                .thenReturn(List.of(resolveInfoToReturn));
+    }
+
+    private void mockBacklinksTaskForMainLauncherIntent() {
+        mockPmToResolveForMainLauncherIntent(BACKLINKS_TASK_RESOLVE_INFO);
+    }
+
+    private void mockPmToResolveForMainLauncherIntent(ResolveInfo resolveInfo) {
+        Intent intent = new Intent(ACTION_MAIN).addCategory(CATEGORY_LAUNCHER).setPackage(
+                resolveInfo.activityInfo.packageName);
+        when(mPackageManager.resolveActivity(intentEquals(intent), eq(/* flags= */ 0))).thenReturn(
+                resolveInfo);
+        mockPmToLoadAppIcon(resolveInfo);
+    }
+
+    private void mockPmToLoadAppIcon(ResolveInfo resolveInfo) {
+        when(mPackageManager.loadItemIcon(resolveInfo.activityInfo,
+                resolveInfo.activityInfo.applicationInfo)).thenReturn(FAKE_DRAWABLE);
+    }
+
+    private void mockAtmToReturnRunningTaskInfo(RunningTaskInfo... taskInfos)
+            throws RemoteException {
+        when(mAtmService.getTasks(Integer.MAX_VALUE, /* filterOnlyVisibleRecents= */
+                false, /* keepIntentExtras= */ false, DEFAULT_DISPLAY)).thenReturn(
+                List.of(taskInfos));
+    }
+
+    private static Intent intentEquals(Intent intent) {
+        return argThat(new IntentMatcher(intent));
+    }
+
+    private static class IntentMatcher implements ArgumentMatcher<Intent> {
+        private final Intent mExpectedIntent;
+
+        IntentMatcher(Intent expectedIntent) {
+            mExpectedIntent = expectedIntent;
+        }
+
+        @Override
+        public boolean matches(Intent actualIntent) {
+            return actualIntent != null && mExpectedIntent.filterEquals(actualIntent);
+        }
+    }
+
     private static ResolveInfo createBacklinksTaskResolveInfo() {
         ActivityInfo activityInfo = new ActivityInfo();
         activityInfo.applicationInfo = new ApplicationInfo();
@@ -558,7 +564,7 @@
         taskInfo.isRunning = true;
         taskInfo.numActivities = 1;
         taskInfo.topActivity = new ComponentName(BACKLINKS_TASK_PACKAGE_NAME, "backlinksClass");
-        taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
+        taskInfo.topActivityInfo = BACKLINKS_TASK_RESOLVE_INFO.activityInfo;
         taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
         taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
         taskInfo.userId = UserHandle.myUserId();
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 e0c4ab7..4bd0c75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -167,7 +167,7 @@
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 0217238..905301e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -117,11 +117,11 @@
                 deviceProvisionedController,
                 notificationShadeWindowController,
                 0,
+                Lazy { nswvc },
                 Lazy { npvc },
                 Lazy { assistManager },
                 Lazy { gutsManager },
             )
-        shadeController.setNotificationShadeWindowViewController(nswvc)
         shadeController.setVisibilityListener(mock())
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 0846ced..fc2ad60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -244,23 +244,23 @@
     }
 
     @Test
-    fun dualCarrier_disablesCarrierIconsInStatusIcons() {
+    fun dualCarrier_disablesCarrierIconsInStatusIcons_qs() {
         whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false)
 
         makeShadeVisible()
         shadeHeaderController.qsExpandedFraction = 1.0f
 
-        verify(statusIcons).addIgnoredSlots(carrierIconSlots)
+        verify(statusIcons, times(2)).addIgnoredSlots(carrierIconSlots)
     }
 
     @Test
-    fun dualCarrier_enablesCarrierIconsInStatusIcons_qsExpanded() {
+    fun dualCarrier_disablesCarrierIconsInStatusIcons_qqs() {
         whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false)
 
         makeShadeVisible()
         shadeHeaderController.qsExpandedFraction = 0.0f
 
-        verify(statusIcons, times(2)).removeIgnoredSlots(carrierIconSlots)
+        verify(statusIcons, times(2)).addIgnoredSlots(carrierIconSlots)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index b65a902..a1750cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
@@ -27,16 +29,18 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.shadeTestUtil
+import com.android.systemui.shade.shared.flag.DualShade
 import com.android.systemui.testKosmos
-import com.google.common.truth.Truth
 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
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -53,7 +57,12 @@
     private val sceneInteractor = kosmos.sceneInteractor
     private val shadeTestUtil = kosmos.shadeTestUtil
 
-    private val underTest = kosmos.shadeInteractorSceneContainerImpl
+    private lateinit var underTest: ShadeInteractorSceneContainerImpl
+
+    @Before
+    fun setUp() {
+        underTest = kosmos.shadeInteractorSceneContainerImpl
+    }
 
     @Test
     fun qsExpansionWhenInSplitShadeAndQsExpanded() =
@@ -80,7 +89,7 @@
             keyguardRepository.setStatusBarState(StatusBarState.SHADE)
 
             // THEN legacy shade expansion is passed through
-            Truth.assertThat(actual).isEqualTo(.3f)
+            assertThat(actual).isEqualTo(.3f)
         }
 
     @Test
@@ -109,7 +118,7 @@
             runCurrent()
 
             // THEN shade expansion is zero
-            Truth.assertThat(actual).isEqualTo(.7f)
+            assertThat(actual).isEqualTo(.7f)
         }
 
     @Test
@@ -134,7 +143,7 @@
             runCurrent()
 
             // THEN QS is not fullscreen
-            Truth.assertThat(actual).isFalse()
+            assertThat(actual).isFalse()
         }
 
     @Test
@@ -152,7 +161,7 @@
             runCurrent()
 
             // THEN QS is not fullscreen
-            Truth.assertThat(actual).isFalse()
+            assertThat(actual).isFalse()
         }
 
     @Test
@@ -171,7 +180,7 @@
             runCurrent()
 
             // THEN QS is not fullscreen
-            Truth.assertThat(actual).isFalse()
+            assertThat(actual).isFalse()
         }
 
     @Test
@@ -189,7 +198,7 @@
             runCurrent()
 
             // THEN QS is fullscreen
-            Truth.assertThat(actual).isTrue()
+            assertThat(actual).isTrue()
         }
 
     @Test
@@ -206,7 +215,7 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN expansion is 1
-            Truth.assertThat(expansionAmount).isEqualTo(1f)
+            assertThat(expansionAmount).isEqualTo(1f)
         }
 
     @Test
@@ -224,7 +233,7 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN expansion is 0
-            Truth.assertThat(expansionAmount).isEqualTo(0f)
+            assertThat(expansionAmount).isEqualTo(0f)
         }
 
     @Test
@@ -251,19 +260,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN expansion is 0
-            Truth.assertThat(expansionAmount).isEqualTo(0f)
+            assertThat(expansionAmount).isEqualTo(0f)
 
             // WHEN transition state is partially to the scene
             progress.value = .4f
 
             // THEN expansion matches the progress
-            Truth.assertThat(expansionAmount).isEqualTo(.4f)
+            assertThat(expansionAmount).isEqualTo(.4f)
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN expansion is 1
-            Truth.assertThat(expansionAmount).isEqualTo(1f)
+            assertThat(expansionAmount).isEqualTo(1f)
         }
 
     @Test
@@ -290,19 +299,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN expansion is 1
-            Truth.assertThat(expansionAmount).isEqualTo(1f)
+            assertThat(expansionAmount).isEqualTo(1f)
 
             // WHEN transition state is partially to the scene
             progress.value = .4f
 
             // THEN expansion reflects the progress
-            Truth.assertThat(expansionAmount).isEqualTo(.6f)
+            assertThat(expansionAmount).isEqualTo(.6f)
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN expansion is 0
-            Truth.assertThat(expansionAmount).isEqualTo(0f)
+            assertThat(expansionAmount).isEqualTo(0f)
         }
 
     fun isQsBypassingShade_goneToQs() =
@@ -326,7 +335,7 @@
             runCurrent()
 
             // THEN qs is bypassing shade
-            Truth.assertThat(actual).isTrue()
+            assertThat(actual).isTrue()
         }
 
     fun isQsBypassingShade_shadeToQs() =
@@ -350,7 +359,7 @@
             runCurrent()
 
             // THEN qs is not bypassing shade
-            Truth.assertThat(actual).isFalse()
+            assertThat(actual).isFalse()
         }
 
     @Test
@@ -376,19 +385,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN expansion is 0
-            Truth.assertThat(expansionAmount).isEqualTo(0f)
+            assertThat(expansionAmount).isEqualTo(0f)
 
             // WHEN transition state is partially complete
             progress.value = .4f
 
             // THEN expansion is still 0
-            Truth.assertThat(expansionAmount).isEqualTo(0f)
+            assertThat(expansionAmount).isEqualTo(0f)
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN expansion is still 0
-            Truth.assertThat(expansionAmount).isEqualTo(0f)
+            assertThat(expansionAmount).isEqualTo(0f)
         }
 
     @Test
@@ -405,7 +414,7 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
         }
 
     @Test
@@ -432,19 +441,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
 
             // WHEN transition state is partially to the scene
             progress.value = .4f
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
         }
 
     @Test
@@ -471,19 +480,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN interacting is true
-            Truth.assertThat(interacting).isTrue()
+            assertThat(interacting).isTrue()
 
             // WHEN transition state is partially to the scene
             progress.value = .4f
 
             // THEN interacting is true
-            Truth.assertThat(interacting).isTrue()
+            assertThat(interacting).isTrue()
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN interacting is true
-            Truth.assertThat(interacting).isTrue()
+            assertThat(interacting).isTrue()
         }
 
     @Test
@@ -510,19 +519,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
 
             // WHEN transition state is partially to the scene
             progress.value = .4f
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN interacting is false
-            Truth.assertThat(interacting).isFalse()
+            assertThat(interacting).isFalse()
         }
 
     @Test
@@ -549,19 +558,19 @@
             sceneInteractor.setTransitionState(transitionState)
 
             // THEN interacting is true
-            Truth.assertThat(interacting).isTrue()
+            assertThat(interacting).isTrue()
 
             // WHEN transition state is partially to the scene
             progress.value = .4f
 
             // THEN interacting is true
-            Truth.assertThat(interacting).isTrue()
+            assertThat(interacting).isTrue()
 
             // WHEN transition completes
             progress.value = 1f
 
             // THEN interacting is true
-            Truth.assertThat(interacting).isTrue()
+            assertThat(interacting).isTrue()
         }
 
     @Test
@@ -572,7 +581,6 @@
             val interacting by collectLastValue(interactingFlow)
 
             // WHEN transition state is starting to between different scenes
-            val progress = MutableStateFlow(0f)
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
                     ObservableTransitionState.Transition(
@@ -589,4 +597,94 @@
             // THEN interacting is false
             assertThat(interacting).isFalse()
         }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun expandNotificationShade_dualShadeEnabled_opensOverlay() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).isEmpty()
+
+            underTest.expandNotificationShade("reason")
+
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
+        }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun expandNotificationShade_dualShadeDisabled_switchesToShadeScene() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).isEmpty()
+
+            underTest.expandNotificationShade("reason")
+
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(currentOverlays).isEmpty()
+        }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun expandNotificationShade_dualShadeEnabledAndQuickSettingsOpen_replacesOverlay() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            underTest.expandQuickSettingsShade("reason")
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
+
+            underTest.expandNotificationShade("reason")
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
+        }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun expandQuickSettingsShade_dualShadeEnabled_opensOverlay() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).isEmpty()
+
+            underTest.expandQuickSettingsShade("reason")
+
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
+        }
+
+    @Test
+    @DisableFlags(DualShade.FLAG_NAME)
+    fun expandQuickSettingsShade_dualShadeDisabled_switchesToQuickSettingsScene() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).isEmpty()
+
+            underTest.expandQuickSettingsShade("reason")
+
+            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
+            assertThat(currentOverlays).isEmpty()
+        }
+
+    @Test
+    @EnableFlags(DualShade.FLAG_NAME)
+    fun expandQuickSettingsShade_dualShadeEnabledAndNotificationsOpen_replacesOverlay() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+            underTest.expandNotificationShade("reason")
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
+
+            underTest.expandQuickSettingsShade("reason")
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index b4f4138..76bb8de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -43,7 +43,7 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderWrapper.FullScreenIntentDecisionImpl
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.notification.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 import com.android.systemui.util.concurrency.FakeExecutor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 3df4a67..30556be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -103,7 +103,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationListViewBinder;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
+import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
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 c7c08a9..af04309 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
@@ -467,13 +467,12 @@
                     mDeviceProvisionedController,
                     mNotificationShadeWindowController,
                     0,
+                    () -> mNotificationShadeWindowViewController,
                     () -> mNotificationPanelViewController,
                     () -> mAssistManager,
                     () -> mNotificationGutsManager
             ));
         }
-        mShadeController.setNotificationShadeWindowViewController(
-                mNotificationShadeWindowViewController);
         mShadeController.setNotificationPresenter(mNotificationPresenter);
 
         when(mOperatorNameViewControllerFactory.create(any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 93071bd..2588f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -14,10 +14,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf;
-
-import static com.android.settingslib.flags.Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -25,7 +21,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -35,11 +30,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.FlagsParameterization;
+import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
@@ -65,31 +56,16 @@
 import org.junit.Before;
 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.Executor;
 
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
-@RunWith(ParameterizedAndroidJunit4.class)
+@RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
 public class BluetoothControllerImplTest extends SysuiTestCase {
 
-    @Parameters(name = "{0}")
-    public static List<FlagsParameterization> getParams() {
-        return allCombinationsOf(FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE);
-    }
-
-    private static final String TEST_EXCLUSIVE_MANAGER = "com.test.manager";
-
-    @Mock
-    private PackageManager mPackageManager;
-
     private UserTracker mUserTracker;
     private LocalBluetoothManager mMockBluetoothManager;
     private CachedBluetoothDeviceManager mMockDeviceManager;
@@ -102,21 +78,14 @@
 
     private FakeExecutor mBackgroundExecutor;
 
-    public BluetoothControllerImplTest(FlagsParameterization flags) {
-        super();
-        mSetFlagsRule.setFlagsParameterization(flags);
-    }
-
     @Before
     public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
         mTestableLooper = TestableLooper.get(this);
         mMockBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager.class);
         mDevices = new ArrayList<>();
         mUserTracker = mock(UserTracker.class);
         mMockDeviceManager = mock(CachedBluetoothDeviceManager.class);
         mMockAdapter = mock(BluetoothAdapter.class);
-        mContext.setMockPackageManager(mPackageManager);
         when(mMockDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
         when(mMockBluetoothManager.getCachedDeviceManager()).thenReturn(mMockDeviceManager);
         mMockLocalAdapter = mock(LocalBluetoothAdapter.class);
@@ -146,7 +115,6 @@
         CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
         when(device.isConnected()).thenReturn(true);
         when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
-        when(device.getDevice()).thenReturn(mock(BluetoothDevice.class));
 
         mDevices.add(device);
         when(mMockLocalAdapter.getConnectionState())
@@ -172,12 +140,10 @@
     public void getConnectedDevices_onlyReturnsConnected() {
         CachedBluetoothDevice device1Disconnected = mock(CachedBluetoothDevice.class);
         when(device1Disconnected.isConnected()).thenReturn(false);
-        when(device1Disconnected.getDevice()).thenReturn(mock(BluetoothDevice.class));
         mDevices.add(device1Disconnected);
 
         CachedBluetoothDevice device2Connected = mock(CachedBluetoothDevice.class);
         when(device2Connected.isConnected()).thenReturn(true);
-        when(device2Connected.getDevice()).thenReturn(mock(BluetoothDevice.class));
         mDevices.add(device2Connected);
 
         mBluetoothControllerImpl.onDeviceAdded(device1Disconnected);
@@ -189,46 +155,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    public void getConnectedDevice_exclusivelyManagedDevice_doNotReturn()
-            throws PackageManager.NameNotFoundException {
-        CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
-        when(cachedDevice.isConnected()).thenReturn(true);
-        BluetoothDevice device = mock(BluetoothDevice.class);
-        when(device.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
-                TEST_EXCLUSIVE_MANAGER.getBytes());
-        when(cachedDevice.getDevice()).thenReturn(device);
-        doReturn(new ApplicationInfo()).when(mPackageManager).getApplicationInfo(
-                TEST_EXCLUSIVE_MANAGER, 0);
-
-        mDevices.add(cachedDevice);
-        mBluetoothControllerImpl.onDeviceAdded(cachedDevice);
-
-        assertThat(mBluetoothControllerImpl.getConnectedDevices()).isEmpty();
-    }
-
-    @Test
-    @DisableFlags(FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    public void getConnectedDevice_exclusivelyManagedDevice_returnsConnected()
-            throws PackageManager.NameNotFoundException {
-        CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
-        when(cachedDevice.isConnected()).thenReturn(true);
-        BluetoothDevice device = mock(BluetoothDevice.class);
-        when(device.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
-                TEST_EXCLUSIVE_MANAGER.getBytes());
-        when(cachedDevice.getDevice()).thenReturn(device);
-        doReturn(new ApplicationInfo()).when(mPackageManager).getApplicationInfo(
-                TEST_EXCLUSIVE_MANAGER, 0);
-
-        mDevices.add(cachedDevice);
-        mBluetoothControllerImpl.onDeviceAdded(cachedDevice);
-
-        assertThat(mBluetoothControllerImpl.getConnectedDevices()).hasSize(1);
-        assertThat(mBluetoothControllerImpl.getConnectedDevices().get(0))
-                .isEqualTo(cachedDevice);
-    }
-
-    @Test
     public void testOnBluetoothStateChange_updatesBluetoothState() {
         mBluetoothControllerImpl.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
 
@@ -259,7 +185,6 @@
 
         assertFalse(mBluetoothControllerImpl.isBluetoothConnected());
         CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
-        when(device.getDevice()).thenReturn(mock(BluetoothDevice.class));
         mDevices.add(device);
         when(device.isConnected()).thenReturn(true);
         when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
@@ -478,7 +403,6 @@
     private CachedBluetoothDevice createBluetoothDevice(
             int profile, boolean isConnected, boolean isActive) {
         CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
-        when(device.getDevice()).thenReturn(mock(BluetoothDevice.class));
         mDevices.add(device);
         when(device.isActiveDevice(profile)).thenReturn(isActive);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
index cafebb9..d059c14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
@@ -38,8 +38,7 @@
 
     companion object {
         const val THRESHOLD_VELOCITY_PX_PER_MS = 0.1f
-        // multiply by 1000 to get px per ms instead of px per s which is unit used by velocity
-        // tracker
+        // multiply by 1000 to get px/ms instead of px/s which is unit used by velocity tracker
         const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS * 1000 - 1
         const val FAST = THRESHOLD_VELOCITY_PX_PER_MS * 1000 + 1
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt
index d31491d..25c4bbb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt
@@ -18,4 +18,6 @@
 
 import com.android.systemui.kosmos.Kosmos
 
-var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { FalsingCollectorFake() }
+var Kosmos.fakeFalsingCollector by Kosmos.Fixture { FalsingCollectorFake() }
+
+var Kosmos.falsingCollector by Kosmos.Fixture<FalsingCollector> { fakeFalsingCollector }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
index 13116e7..096022c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.keyguard.dismissCallbackRegistry
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
@@ -36,5 +37,6 @@
             deviceUnlockedInteractor = deviceUnlockedInteractor,
             alternateBouncerInteractor = alternateBouncerInteractor,
             dismissCallbackRegistry = dismissCallbackRegistry,
+            sceneBackInteractor = sceneBackInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt
new file mode 100644
index 0000000..94982ed
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/BouncerHapticHelperKosmos.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.haptics.msdl
+
+import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer
+import com.android.systemui.kosmos.Kosmos
+import com.google.android.msdl.domain.MSDLPlayer
+import dagger.Lazy
+
+val Kosmos.bouncerHapticPlayer: BouncerHapticPlayer by
+    Kosmos.Fixture {
+        val lazyPlayer = Lazy<MSDLPlayer> { fakeMSDLPlayer }
+        BouncerHapticPlayer(lazyPlayer)
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index c60305e..f97f303 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.globalactions.domain.interactor.globalActionsInteractor
+import com.android.systemui.haptics.msdl.bouncerHapticPlayer
 import com.android.systemui.haptics.msdl.fakeMSDLPlayer
 import com.android.systemui.haptics.qs.qsLongPressEffect
 import com.android.systemui.jank.interactionJankMonitor
@@ -158,4 +159,5 @@
     val sceneContainerOcclusionInteractor by lazy { kosmos.sceneContainerOcclusionInteractor }
     val msdlPlayer by lazy { kosmos.fakeMSDLPlayer }
     val shadeModeInteractor by lazy { kosmos.shadeModeInteractor }
+    val bouncerHapticHelper by lazy { kosmos.bouncerHapticPlayer }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
index 9a5698c..4228c3c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
@@ -32,13 +32,11 @@
 import com.android.systemui.keyguard.dismissCallbackRegistry
 import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.model.sysUiState
-import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.scene.domain.interactor.sceneBackInteractor
 import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
@@ -62,7 +60,6 @@
         deviceUnlockedInteractor = deviceUnlockedInteractor,
         bouncerInteractor = bouncerInteractor,
         keyguardInteractor = keyguardInteractor,
-        keyguardTransitionInteractor = keyguardTransitionInteractor,
         sysUiState = sysUiState,
         displayId = displayTracker.defaultDisplayId,
         sceneLogger = sceneLogger,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index 0bc4d54..ddcc6d6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -71,6 +71,7 @@
             deviceProvisionedController,
             mock<NotificationShadeWindowController>(),
             0,
+            { mock<NotificationShadeWindowViewController>() },
             { mock<NotificationPanelViewController>() },
             { mock<AssistManager>() },
             { mock<NotificationGutsManager>() },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 04d930c..92075ea 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -44,7 +44,7 @@
         ShadeInteractorSceneContainerImpl(
             scope = applicationCoroutineScope,
             sceneInteractor = sceneInteractor,
-            shadeRepository = shadeRepository,
+            shadeModeInteractor = shadeModeInteractor,
         )
     }
 val Kosmos.shadeInteractorLegacyImpl by
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/TestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/TestUtils.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/TestUtils.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/util/TestUtils.kt
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 3c65f37..d0ea474 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -5,6 +5,10 @@
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_base_license"],
+
+    // OWNER: g/ravenwood
+    // Bug component: 25698
+    default_team: "trendy_team_framework_backstage_power",
 }
 
 filegroup {
diff --git a/ravenwood/OWNERS b/ravenwood/OWNERS
index f7b13d1..8722ad9 100644
--- a/ravenwood/OWNERS
+++ b/ravenwood/OWNERS
@@ -1,5 +1,7 @@
+# Bug component: 25698
 set noparent
 
+omakoto@google.com
 topjohnwu@google.com
 hackbod@google.com  #{LAST_RESORT_SUGGESTION}
 
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index b97ff62..9fd2f31 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -20,11 +20,6 @@
     defaults: [
         "platform_service_defaults",
     ],
-    lint: {
-        error_checks: ["MissingPermissionAnnotation"],
-        baseline_filename: "lint-baseline.xml",
-
-    },
     srcs: [
         ":services.accessibility-sources",
         "//frameworks/base/packages/SettingsLib/RestrictedLockUtils:SettingsLibRestrictedLockUtilsSrc",
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 1b2447e..617cca9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -67,7 +67,6 @@
  *
  * NOTE: This class has to be created and poked only from the main thread.
  */
-@SuppressWarnings("MissingPermissionAnnotation")
 class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
 
     private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
index e10e87c..c9ec16e 100644
--- a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -33,7 +33,6 @@
 /**
  * Encapsulate fingerprint gesture logic
  */
-@SuppressWarnings("MissingPermissionAnnotation")
 public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
         implements Handler.Callback{
     private static final int MSG_REGISTER = 1;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
new file mode 100644
index 0000000..c3b7087
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
@@ -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.server.appfunctions;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/** Executors for App function operations. */
+public final class AppFunctionExecutors {
+
+    /** Executor for operations that do not need to block. */
+    public static final Executor THREAD_POOL_EXECUTOR =
+            new ThreadPoolExecutor(
+                    /* corePoolSize= */ Runtime.getRuntime().availableProcessors(),
+                    /* maxConcurrency= */ Runtime.getRuntime().availableProcessors(),
+                    /* keepAliveTime= */ 0L,
+                    /* unit= */ TimeUnit.SECONDS,
+                    /* workQueue= */ new LinkedBlockingQueue<>());
+
+    private AppFunctionExecutors() {}
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index f04bd9f..269419f 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.appfunctions;
 
+import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR;
+
 import android.annotation.NonNull;
 import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
 import android.app.appfunctions.ExecuteAppFunctionResponse;
@@ -29,6 +31,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Slog;
+import android.app.appsearch.AppSearchResult;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
@@ -51,14 +54,7 @@
     public AppFunctionManagerServiceImpl(@NonNull Context context) {
         this(
                 new RemoteServiceCallerImpl<>(
-                        context,
-                        IAppFunctionService.Stub::asInterface,
-                        new ThreadPoolExecutor(
-                                /* corePoolSize= */ Runtime.getRuntime().availableProcessors(),
-                                /* maxConcurrency= */ Runtime.getRuntime().availableProcessors(),
-                                /* keepAliveTime= */ 0L,
-                                /* unit= */ TimeUnit.SECONDS,
-                                /* workQueue= */ new LinkedBlockingQueue<>())),
+                        context, IAppFunctionService.Stub::asInterface, THREAD_POOL_EXECUTOR),
                 new CallerValidatorImpl(context),
                 new ServiceHelperImpl(context),
                 new ServiceConfigImpl());
@@ -86,6 +82,17 @@
         final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
                 new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback);
 
+        try {
+            executeAppFunctionInternal(requestInternal, safeExecuteAppFunctionCallback);
+        } catch (Exception e) {
+            safeExecuteAppFunctionCallback.onResult(mapExceptionToExecuteAppFunctionResponse(e));
+        }
+    }
+
+    private void executeAppFunctionInternal(
+            ExecuteAppFunctionAidlRequest requestInternal,
+            SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
+
         String validatedCallingPackage;
         UserHandle targetUser;
         try {
@@ -124,39 +131,53 @@
             return;
         }
 
-        if (!mCallerValidator.verifyCallerCanExecuteAppFunction(
-                validatedCallingPackage, targetPackageName)) {
-            safeExecuteAppFunctionCallback.onResult(
-                    ExecuteAppFunctionResponse.newFailure(
-                            ExecuteAppFunctionResponse.RESULT_DENIED,
-                            "Caller does not have permission to execute the appfunction",
-                            /* extras= */ null));
-            return;
-        }
-
-        Intent serviceIntent =
-                mInternalServiceHelper.resolveAppFunctionService(targetPackageName, targetUser);
-        if (serviceIntent == null) {
-            safeExecuteAppFunctionCallback.onResult(
-                    ExecuteAppFunctionResponse.newFailure(
-                            ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
-                            "Cannot find the target service.",
-                            /* extras= */ null));
-            return;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            bindAppFunctionServiceUnchecked(
-                    requestInternal,
-                    serviceIntent,
-                    targetUser,
-                    safeExecuteAppFunctionCallback,
-                    /* bindFlags= */ Context.BIND_AUTO_CREATE,
-                    /* timeoutInMillis= */ mServiceConfig.getExecuteAppFunctionTimeoutMillis());
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        var unused = mCallerValidator
+                .verifyCallerCanExecuteAppFunction(
+                        validatedCallingPackage,
+                        targetPackageName,
+                        requestInternal.getClientRequest().getFunctionIdentifier())
+                .thenAccept(
+                        canExecute -> {
+                            if (!canExecute) {
+                                safeExecuteAppFunctionCallback.onResult(
+                                        ExecuteAppFunctionResponse.newFailure(
+                                                ExecuteAppFunctionResponse.RESULT_DENIED,
+                                                "Caller does not have permission to execute the"
+                                                        + " appfunction",
+                                                /* extras= */ null));
+                                return;
+                            }
+                            Intent serviceIntent =
+                                    mInternalServiceHelper.resolveAppFunctionService(
+                                            targetPackageName, targetUser);
+                            if (serviceIntent == null) {
+                                safeExecuteAppFunctionCallback.onResult(
+                                        ExecuteAppFunctionResponse.newFailure(
+                                                ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+                                                "Cannot find the target service.",
+                                                /* extras= */ null));
+                                return;
+                            }
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                                bindAppFunctionServiceUnchecked(
+                                        requestInternal,
+                                        serviceIntent,
+                                        targetUser,
+                                        safeExecuteAppFunctionCallback,
+                                        /* bindFlags= */ Context.BIND_AUTO_CREATE,
+                                        /* timeoutInMillis= */ mServiceConfig
+                                                .getExecuteAppFunctionTimeoutMillis());
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        })
+                .exceptionally(
+                        ex -> {
+                            safeExecuteAppFunctionCallback.onResult(
+                                    mapExceptionToExecuteAppFunctionResponse(ex));
+                            return null;
+                        });
     }
 
     private void bindAppFunctionServiceUnchecked(
@@ -232,4 +253,37 @@
                             /* extras= */ null));
         }
     }
+
+    private ExecuteAppFunctionResponse mapExceptionToExecuteAppFunctionResponse(Throwable e) {
+        if (e instanceof AppSearchException) {
+            AppSearchException appSearchException = (AppSearchException) e;
+            return ExecuteAppFunctionResponse.newFailure(
+                    mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(
+                            appSearchException.getResultCode()),
+                    appSearchException.getMessage(),
+                    /* extras= */ null);
+        }
+
+        return ExecuteAppFunctionResponse.newFailure(
+                ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+                e.getMessage(),
+                /* extras= */ null);
+    }
+
+    private int mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(int resultCode) {
+        if (resultCode == AppSearchResult.RESULT_OK) {
+            throw new IllegalArgumentException(
+                    "This method can only be used to convert failure result codes.");
+        }
+
+        switch (resultCode) {
+            case AppSearchResult.RESULT_NOT_FOUND:
+                return ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT;
+            case AppSearchResult.RESULT_INVALID_ARGUMENT:
+            case AppSearchResult.RESULT_INTERNAL_ERROR:
+            case AppSearchResult.RESULT_SECURITY_ERROR:
+                // fall-through
+        }
+        return ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR;
+    }
 }
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java b/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java
new file mode 100644
index 0000000..c23470a
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppSearchException.java
@@ -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.server.appfunctions;
+
+import android.app.appsearch.AppSearchResult;
+
+/** Exception to wrap failure result codes returned by AppSearch. */
+public class AppSearchException extends RuntimeException {
+    private final int resultCode;
+
+    public AppSearchException(int resultCode, String message) {
+        super(message);
+        this.resultCode = resultCode;
+    }
+
+    /**
+     * Returns the result code used to create this exception, typically one of the {@link
+     * AppSearchResult} result codes.
+     */
+    public int getResultCode() {
+        return resultCode;
+    }
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
index ca43dfa..e7a861e 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
@@ -21,6 +21,7 @@
 import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
 
 /**
  * Interface for validating that the caller has the correct privilege to call an AppFunctionManager
@@ -65,10 +66,13 @@
      *
      * @param callerPackageName The calling package (as previously validated).
      * @param targetPackageName The package that owns the app function to execute.
+     * @param functionId The id of the app function to execute.
      * @return Whether the caller can execute the specified app function.
      */
-    boolean verifyCallerCanExecuteAppFunction(
-            @NonNull String callerPackageName, @NonNull String targetPackageName);
+    AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction(
+            @NonNull String callerPackageName,
+            @NonNull String targetPackageName,
+            @NonNull String functionId);
 
     /**
      * Checks if the user is organization managed.
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
index 618a5ae..94a63b4 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
@@ -16,11 +16,23 @@
 
 package com.android.server.appfunctions;
 
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction;
+import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR;
+
 import android.Manifest;
 import android.annotation.BinderThread;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.app.admin.DevicePolicyManager;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchManager.SearchContext;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.GenericDocument;
+import android.app.appsearch.GetByDocumentIdRequest;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -28,6 +40,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import com.android.internal.infra.AndroidFuture;
 import java.util.Objects;
 
 /* Validates that caller has the correct privilege to call an AppFunctionManager Api. */
@@ -76,11 +89,12 @@
                 Manifest.permission.EXECUTE_APP_FUNCTIONS
             },
             conditional = true)
-    // TODO(b/360864791): Add and honor apps that opt-out from EXECUTE_APP_FUNCTIONS caller.
-    public boolean verifyCallerCanExecuteAppFunction(
-            @NonNull String callerPackageName, @NonNull String targetPackageName) {
+    public AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction(
+            @NonNull String callerPackageName,
+            @NonNull String targetPackageName,
+            @NonNull String functionId) {
         if (callerPackageName.equals(targetPackageName)) {
-            return true;
+            return AndroidFuture.completedFuture(true);
         }
 
         int pid = Binder.getCallingPid();
@@ -89,10 +103,67 @@
                 mContext.checkPermission(
                                 Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, pid, uid)
                         == PackageManager.PERMISSION_GRANTED;
+
+        if (hasTrustedExecutionPermission) {
+            return AndroidFuture.completedFuture(true);
+        }
+
         boolean hasExecutionPermission =
                 mContext.checkPermission(Manifest.permission.EXECUTE_APP_FUNCTIONS, pid, uid)
                         == PackageManager.PERMISSION_GRANTED;
-        return hasExecutionPermission || hasTrustedExecutionPermission;
+
+        if (!hasExecutionPermission) {
+            return AndroidFuture.completedFuture(false);
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            FutureAppSearchSession futureAppSearchSession =
+                    new FutureAppSearchSessionImpl(
+                            mContext.getSystemService(AppSearchManager.class),
+                            THREAD_POOL_EXECUTOR,
+                            new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build());
+
+            String documentId = getDocumentIdForAppFunction(targetPackageName, functionId);
+
+            return futureAppSearchSession
+                    .getByDocumentId(
+                            new GetByDocumentIdRequest.Builder(APP_FUNCTION_STATIC_NAMESPACE)
+                                    .addIds(documentId)
+                                    .build())
+                    .thenApply(
+                            batchResult ->
+                                    getGenericDocumentFromBatchResult(batchResult, documentId))
+                    .thenApply(
+                            CallerValidatorImpl::getRestrictCallersWithExecuteAppFunctionsProperty)
+                    .thenApply(
+                            restrictCallersWithExecuteAppFunctions ->
+                                    !restrictCallersWithExecuteAppFunctions
+                                            && hasExecutionPermission);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private static GenericDocument getGenericDocumentFromBatchResult(
+            AppSearchBatchResult<String, GenericDocument> result, String documentId) {
+        if (result.isSuccess()) {
+            return result.getSuccesses().get(documentId);
+        }
+
+        AppSearchResult<GenericDocument> failedResult = result.getFailures().get(documentId);
+        throw new AppSearchException(
+                failedResult.getResultCode(),
+                "Unable to retrieve document with id: "
+                        + documentId
+                        + " due to "
+                        + failedResult.getErrorMessage());
+    }
+
+    private static boolean getRestrictCallersWithExecuteAppFunctionsProperty(
+            GenericDocument genericDocument) {
+        return genericDocument.getPropertyBoolean(
+                STATIC_PROPERTY_RESTRICT_CALLERS_WITH_EXECUTE_APP_FUNCTIONS);
     }
 
     @Override
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index b1c25c4..56f373d 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -26,7 +26,6 @@
 import android.app.appsearch.PutDocumentsRequest;
 import android.app.appsearch.RemoveByDocumentIdRequest;
 import android.app.appsearch.SearchResult;
-import android.app.appsearch.SearchResults;
 import android.app.appsearch.SearchSpec;
 import android.app.appsearch.SetSchemaRequest;
 import android.app.appsearch.SetSchemaResponse;
@@ -36,8 +35,6 @@
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
 
 /** A future API wrapper of {@link AppSearchSession} APIs. */
 public interface FutureAppSearchSession extends Closeable {
@@ -88,29 +85,15 @@
             @NonNull String queryExpression, @NonNull SearchSpec searchSpec);
 
     /** A future API wrapper of {@link android.app.appsearch.SearchResults}. */
-    class FutureSearchResults {
-        private final SearchResults mSearchResults;
-        private final Executor mExecutor;
+    interface FutureSearchResults {
 
-        public FutureSearchResults(
-                @NonNull SearchResults searchResults, @NonNull Executor executor) {
-            mSearchResults = Objects.requireNonNull(searchResults);
-            mExecutor = Objects.requireNonNull(executor);
-        }
-
-        public AndroidFuture<List<SearchResult>> getNextPage() {
-            AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture =
-                    new AndroidFuture<>();
-
-            mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
-            return nextPageFuture.thenApply(
-                    result -> {
-                        if (result.isSuccess()) {
-                            return result.getResultValue();
-                        } else {
-                            throw new RuntimeException(failedResultToException(result));
-                        }
-                    });
-        }
+        /**
+         * Retrieves the next page of {@link SearchResult} objects from the {@link AppSearchSession}
+         * database.
+         *
+         * <p>Continue calling this method to access results until it returns an empty list,
+         * signifying there are no more results.
+         */
+        AndroidFuture<List<SearchResult>> getNextPage();
     }
 }
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
index e78f390..3079d9f 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSessionImpl.java
@@ -30,6 +30,8 @@
 import android.app.appsearch.GetSchemaResponse;
 import android.app.appsearch.PutDocumentsRequest;
 import android.app.appsearch.RemoveByDocumentIdRequest;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResults;
 import android.app.appsearch.SearchSpec;
 import android.app.appsearch.SetSchemaRequest;
 import android.app.appsearch.SetSchemaResponse;
@@ -37,6 +39,7 @@
 import com.android.internal.infra.AndroidFuture;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
@@ -176,12 +179,39 @@
             @NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
         return getSessionAsync()
                 .thenApply(session -> session.search(queryExpression, searchSpec))
-                .thenApply(result -> new FutureSearchResults(result, mExecutor));
+                .thenApply(result -> new FutureSearchResultsImpl(result, mExecutor));
     }
 
     @Override
     public void close() throws IOException {}
 
+    private static final class FutureSearchResultsImpl implements FutureSearchResults {
+        private final SearchResults mSearchResults;
+        private final Executor mExecutor;
+
+        private FutureSearchResultsImpl(
+                @NonNull SearchResults searchResults, @NonNull Executor executor) {
+            this.mSearchResults = searchResults;
+            this.mExecutor = executor;
+        }
+
+        @Override
+        public AndroidFuture<List<SearchResult>> getNextPage() {
+            AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture =
+                    new AndroidFuture<>();
+
+            mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
+            return nextPageFuture.thenApply(
+                    result -> {
+                        if (result.isSuccess()) {
+                            return result.getResultValue();
+                        } else {
+                            throw new RuntimeException(failedResultToException(result));
+                        }
+                    });
+        }
+    }
+
     private static final class BatchResultCallbackAdapter<K, V>
             implements BatchResultCallback<K, V> {
         private final AndroidFuture<AppSearchBatchResult<K, V>> mFuture;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
index 01e1008..5f60804 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
@@ -16,35 +16,238 @@
 
 package com.android.server.appfunctions;
 
+import static android.app.appfunctions.AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.WorkerThread;
+import android.app.appfunctions.AppFunctionRuntimeMetadata;
+import android.app.appfunctions.AppFunctionStaticMetadataHelper;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.PackageIdentifier;
 import android.app.appsearch.PropertyPath;
+import android.app.appsearch.PutDocumentsRequest;
+import android.app.appsearch.RemoveByDocumentIdRequest;
 import android.app.appsearch.SearchResult;
 import android.app.appsearch.SearchSpec;
+import android.app.appsearch.SetSchemaRequest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
 import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults;
 
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 /**
  * This class implements helper methods for synchronously interacting with AppSearch while
  * synchronizing AppFunction runtime and static metadata.
+ *
+ * <p>This class is not thread safe.
  */
 public class MetadataSyncAdapter {
+    private static final String TAG = MetadataSyncAdapter.class.getSimpleName();
     private final FutureAppSearchSession mFutureAppSearchSession;
     private final Executor mSyncExecutor;
+    private final PackageManager mPackageManager;
+
+    // Hidden constants in {@link SetSchemaRequest} that restricts runtime metadata visibility
+    // by permissions.
+    public static final int EXECUTE_APP_FUNCTIONS = 9;
+    public static final int EXECUTE_APP_FUNCTIONS_TRUSTED = 10;
 
     public MetadataSyncAdapter(
             @NonNull Executor syncExecutor,
-            @NonNull FutureAppSearchSession futureAppSearchSession) {
+            @NonNull FutureAppSearchSession futureAppSearchSession,
+            @NonNull PackageManager packageManager) {
         mSyncExecutor = Objects.requireNonNull(syncExecutor);
         mFutureAppSearchSession = Objects.requireNonNull(futureAppSearchSession);
+        mPackageManager = Objects.requireNonNull(packageManager);
+    }
+
+    /**
+     * This method submits a request to synchronize the AppFunction runtime and static metadata.
+     *
+     * @return A {@link AndroidFuture} that completes with a boolean value indicating whether the
+     *     synchronization was successful.
+     */
+    public AndroidFuture<Boolean> submitSyncRequest() {
+        AndroidFuture<Boolean> settableSyncStatus = new AndroidFuture<>();
+        mSyncExecutor.execute(
+                () -> {
+                    try {
+                        trySyncAppFunctionMetadataBlocking();
+                        settableSyncStatus.complete(true);
+                    } catch (Exception e) {
+                        settableSyncStatus.completeExceptionally(e);
+                    }
+                });
+        return settableSyncStatus;
+    }
+
+    @WorkerThread
+    private void trySyncAppFunctionMetadataBlocking()
+            throws ExecutionException, InterruptedException {
+        ArrayMap<String, ArraySet<String>> staticPackageToFunctionMap =
+                getPackageToFunctionIdMap(
+                        AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
+                        AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
+                        AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME);
+        ArrayMap<String, ArraySet<String>> runtimePackageToFunctionMap =
+                getPackageToFunctionIdMap(
+                        RUNTIME_SCHEMA_TYPE,
+                        AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
+                        AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME);
+
+        ArrayMap<String, ArraySet<String>> addedFunctionsDiffMap =
+                getAddedFunctionsDiffMap(staticPackageToFunctionMap, runtimePackageToFunctionMap);
+        ArrayMap<String, ArraySet<String>> removedFunctionsDiffMap =
+                getRemovedFunctionsDiffMap(staticPackageToFunctionMap, runtimePackageToFunctionMap);
+
+        Set<AppSearchSchema> appRuntimeMetadataSchemas =
+                getAllRuntimeMetadataSchemas(staticPackageToFunctionMap.keySet());
+        appRuntimeMetadataSchemas.add(
+                AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema());
+
+        // Operation order matters here. i.e. remove -> setSchema -> add. Otherwise we would
+        // encounter an error trying to delete a document with no existing schema.
+        if (!removedFunctionsDiffMap.isEmpty()) {
+            RemoveByDocumentIdRequest removeByDocumentIdRequest =
+                    buildRemoveRuntimeMetadataRequest(removedFunctionsDiffMap);
+            AppSearchBatchResult<String, Void> removeDocumentBatchResult =
+                    mFutureAppSearchSession.remove(removeByDocumentIdRequest).get();
+            if (!removeDocumentBatchResult.isSuccess()) {
+                throw convertFailedAppSearchResultToException(
+                        removeDocumentBatchResult.getFailures().values());
+            }
+        }
+
+        if (!addedFunctionsDiffMap.isEmpty()) {
+            // TODO(b/357551503): only set schema on package diff
+            SetSchemaRequest addSetSchemaRequest =
+                    buildSetSchemaRequestForRuntimeMetadataSchemas(appRuntimeMetadataSchemas);
+            Objects.requireNonNull(mFutureAppSearchSession.setSchema(addSetSchemaRequest).get());
+            PutDocumentsRequest putDocumentsRequest =
+                    buildPutRuntimeMetadataRequest(addedFunctionsDiffMap);
+            AppSearchBatchResult<String, Void> putDocumentBatchResult =
+                    mFutureAppSearchSession.put(putDocumentsRequest).get();
+            if (!putDocumentBatchResult.isSuccess()) {
+                throw convertFailedAppSearchResultToException(
+                        putDocumentBatchResult.getFailures().values());
+            }
+        }
+    }
+
+    @NonNull
+    private static IllegalStateException convertFailedAppSearchResultToException(
+            @NonNull Collection<AppSearchResult<Void>> appSearchResult) {
+        Objects.requireNonNull(appSearchResult);
+        StringBuilder errorMessages = new StringBuilder();
+        for (AppSearchResult<Void> result : appSearchResult) {
+            errorMessages.append(result.getErrorMessage());
+        }
+        return new IllegalStateException(errorMessages.toString());
+    }
+
+    @NonNull
+    private PutDocumentsRequest buildPutRuntimeMetadataRequest(
+            @NonNull ArrayMap<String, ArraySet<String>> addedFunctionsDiffMap) {
+        Objects.requireNonNull(addedFunctionsDiffMap);
+        PutDocumentsRequest.Builder putDocumentRequestBuilder = new PutDocumentsRequest.Builder();
+
+        for (int i = 0; i < addedFunctionsDiffMap.size(); i++) {
+            String packageName = addedFunctionsDiffMap.keyAt(i);
+            ArraySet<String> addedFunctionIds = addedFunctionsDiffMap.valueAt(i);
+            for (String addedFunctionId : addedFunctionIds) {
+                putDocumentRequestBuilder.addGenericDocuments(
+                        new AppFunctionRuntimeMetadata.Builder(
+                                        packageName,
+                                        addedFunctionId,
+                                        AppFunctionRuntimeMetadata
+                                                .PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+                                .build());
+            }
+        }
+        return putDocumentRequestBuilder.build();
+    }
+
+    @NonNull
+    private RemoveByDocumentIdRequest buildRemoveRuntimeMetadataRequest(
+            @NonNull ArrayMap<String, ArraySet<String>> removedFunctionsDiffMap) {
+        Objects.requireNonNull(AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE);
+        Objects.requireNonNull(removedFunctionsDiffMap);
+        RemoveByDocumentIdRequest.Builder removeDocumentRequestBuilder =
+                new RemoveByDocumentIdRequest.Builder(
+                        AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE);
+
+        for (int i = 0; i < removedFunctionsDiffMap.size(); i++) {
+            String packageName = removedFunctionsDiffMap.keyAt(i);
+            ArraySet<String> removedFunctionIds = removedFunctionsDiffMap.valueAt(i);
+            for (String functionId : removedFunctionIds) {
+                String documentId =
+                        AppFunctionRuntimeMetadata.getDocumentIdForAppFunction(
+                                packageName, functionId);
+                removeDocumentRequestBuilder.addIds(documentId);
+            }
+        }
+        return removeDocumentRequestBuilder.build();
+    }
+
+    @NonNull
+    private SetSchemaRequest buildSetSchemaRequestForRuntimeMetadataSchemas(
+            @NonNull Set<AppSearchSchema> metadataSchemaSet) {
+        Objects.requireNonNull(metadataSchemaSet);
+        SetSchemaRequest.Builder setSchemaRequestBuilder =
+                new SetSchemaRequest.Builder().setForceOverride(true).addSchemas(metadataSchemaSet);
+
+        for (AppSearchSchema runtimeMetadataSchema : metadataSchemaSet) {
+            String packageName =
+                    AppFunctionRuntimeMetadata.getPackageNameFromSchema(
+                            runtimeMetadataSchema.getSchemaType());
+            byte[] packageCert = getCertificate(packageName);
+            if (packageCert == null) {
+                continue;
+            }
+            setSchemaRequestBuilder.setSchemaTypeVisibilityForPackage(
+                    runtimeMetadataSchema.getSchemaType(),
+                    true,
+                    new PackageIdentifier(packageName, packageCert));
+        }
+
+        setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+                RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS));
+        setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+                RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS_TRUSTED));
+        return setSchemaRequestBuilder.build();
+    }
+
+    @NonNull
+    @WorkerThread
+    private Set<AppSearchSchema> getAllRuntimeMetadataSchemas(
+            @NonNull Set<String> staticMetadataPackages) {
+        Objects.requireNonNull(staticMetadataPackages);
+
+        Set<AppSearchSchema> appRuntimeMetadataSchemas = new ArraySet<>();
+        for (String packageName : staticMetadataPackages) {
+            appRuntimeMetadataSchemas.add(
+                    AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(packageName));
+        }
+
+        return appRuntimeMetadataSchemas;
     }
 
     /**
@@ -188,4 +391,39 @@
                                 new PropertyPath(propertyPackageName)))
                 .build();
     }
+
+    /** Gets the SHA-256 certificate from a {@link PackageManager}, or null if it is not found. */
+    @Nullable
+    private byte[] getCertificate(@NonNull String packageName) {
+        Objects.requireNonNull(packageName);
+        PackageInfo packageInfo;
+        try {
+            packageInfo =
+                    Objects.requireNonNull(
+                            mPackageManager.getPackageInfo(
+                                    packageName,
+                                    PackageManager.GET_META_DATA
+                                            | PackageManager.GET_SIGNING_CERTIFICATES));
+        } catch (Exception e) {
+            Slog.d(TAG, "Package name info not found for package: " + packageName);
+            return null;
+        }
+        if (packageInfo.signingInfo == null) {
+            Slog.d(TAG, "Signing info not found for package: " + packageInfo.packageName);
+            return null;
+        }
+
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("SHA256");
+        } catch (NoSuchAlgorithmException e) {
+            return null;
+        }
+        Signature[] signatures = packageInfo.signingInfo.getSigningCertificateHistory();
+        if (signatures == null || signatures.length == 0) {
+            return null;
+        }
+        md.update(signatures[0].toByteArray());
+        return md.digest();
+    }
 }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 556fae3..30f3fd2 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -78,24 +78,11 @@
             "file_patterns": ["StorageManagerService\\.java"]
         },
         {
-            "name": "FrameworksServicesTests",
-            "options": [
-                {
-                    "include-filter": "com.android.server.BinaryTransparencyServiceTest"
-                }
-            ],
+            "name": "FrameworksServicesTests_binary_transparency",
             "file_patterns": ["BinaryTransparencyService\\.java"]
         },
         {
-            "name": "FrameworksServicesTests",
-            "options": [
-                {
-                    "include-filter": "com.android.server.PinnerServiceTest"
-                },
-                {
-                    "exclude-annotation": "org.junit.Ignore"
-                }
-            ],
+            "name": "FrameworksServicesTests_pinner_service",
             "file_patterns": ["PinnerService\\.java"]
         },
         {
@@ -176,15 +163,7 @@
             "name": "CtsPackageManagerTestCases"
         },
         {
-            "name": "FrameworksServicesTests",
-            "options": [
-                {
-                    "include-filter": "com.android.server.PinnerServiceTest"
-                },
-                {
-                    "exclude-annotation": "org.junit.Ignore"
-                }
-            ],
+            "name": "FrameworksServicesTests_pinner_service",
             "file_patterns": ["PinnerService\\.java"]
         },
         {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index f5a297b..6fd281e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -685,6 +685,11 @@
     // default. Controlled by Settings.Global.FORCE_ENABLE_PSS_PROFILING
     volatile boolean mForceEnablePssProfiling = false;
 
+    // Indicates whether to use ApplicationInfo to determine launched state instead of PM user state
+    // This is a temporary workaround until the trunk-stable flag is pushed to nextfood.
+    // TODO: b/365979852 - remove this workaround when redundant
+    volatile boolean mFlagUseAppInfoNotLaunched = false;
+
     /**
      * Indicates whether the foreground service background start restriction is enabled for
      * caller app that is targeting S+.
@@ -1017,6 +1022,9 @@
     private static final Uri FORCE_ENABLE_PSS_PROFILING_URI =
             Settings.Global.getUriFor(Settings.Global.FORCE_ENABLE_PSS_PROFILING);
 
+    private static final Uri ENABLE_USE_APP_INFO_NOT_LAUNCHED_URI =
+            Settings.Global.getUriFor(Settings.Global.ENABLE_USE_APP_INFO_NOT_LAUNCHED);
+
     /**
      * The threshold to decide if a given association should be dumped into metrics.
      */
@@ -1479,6 +1487,7 @@
                     false, this);
         }
         mResolver.registerContentObserver(FORCE_ENABLE_PSS_PROFILING_URI, false, this);
+        mResolver.registerContentObserver(ENABLE_USE_APP_INFO_NOT_LAUNCHED_URI, false, this);
         updateConstants();
         if (mSystemServerAutomaticHeapDumpEnabled) {
             updateEnableAutomaticSystemServerHeapDumps();
@@ -1495,6 +1504,7 @@
         updateActivityStartsLoggingEnabled();
         updateForegroundServiceStartsLoggingEnabled();
         updateForceEnablePssProfiling();
+        updateEnableUseAppInfoNotLaunched();
         // Read DropboxRateLimiter params from flags.
         mService.initDropboxRateLimiter();
     }
@@ -1540,6 +1550,8 @@
             updateEnableAutomaticSystemServerHeapDumps();
         } else if (FORCE_ENABLE_PSS_PROFILING_URI.equals(uri)) {
             updateForceEnablePssProfiling();
+        } else if (ENABLE_USE_APP_INFO_NOT_LAUNCHED_URI.equals(uri)) {
+            updateEnableUseAppInfoNotLaunched();
         }
     }
 
@@ -1659,6 +1671,11 @@
                 Settings.Global.FORCE_ENABLE_PSS_PROFILING, 0) == 1;
     }
 
+    private void updateEnableUseAppInfoNotLaunched() {
+        mFlagUseAppInfoNotLaunched = Settings.Global.getInt(mResolver,
+                Settings.Global.ENABLE_USE_APP_INFO_NOT_LAUNCHED, 0) == 1;
+    }
+
     private void updateBackgroundActivityStarts() {
         mFlagBackgroundActivityStartsEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -2538,6 +2555,8 @@
         pw.print("  OOMADJ_UPDATE_QUICK="); pw.println(OOMADJ_UPDATE_QUICK);
         pw.print("  ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION=");
         pw.println(mEnableWaitForFinishAttachApplication);
+        pw.print("  FLAG_USE_APP_INFO_NOT_LAUNCHED=");
+        pw.println(mFlagUseAppInfoNotLaunched);
 
         pw.print("  "); pw.print(KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
         pw.print("="); pw.println(FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3f4902d..2416ab6 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1018,7 +1018,9 @@
         if (Flags.addBatteryUsageStatsSliceAtom()) {
             statsManager.setPullAtomCallback(
                     FrameworkStatsLog.BATTERY_USAGE_STATS_PER_UID,
-                    null, // use default PullAtomMetadata values
+                    new StatsManager.PullAtomMetadata.Builder()
+                            .setTimeoutMillis(3_000L)
+                            .build(),
                     DIRECT_EXECUTOR,
                     pullAtomCallback);
         }
@@ -1098,14 +1100,11 @@
                                     DEVICE_CONFIG_NAMESPACE,
                                     MIN_CONSUMED_POWER_THRESHOLD_KEY,
                                     0);
-                    final long sessionStart = 0;
-                    final long sessionEnd = System.currentTimeMillis();
                     final BatteryUsageStatsQuery query =
                             new BatteryUsageStatsQuery.Builder()
                                     .setMaxStatsAgeMs(0)
                                     .includeProcessStateData()
                                     .includeVirtualUids()
-                                    .aggregateSnapshots(sessionStart, sessionEnd)
                                     .setMinConsumedPowerThreshold(minConsumedPowerThreshold)
                                     .build();
                     bus = getBatteryUsageStats(List.of(query)).get(0);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4898f10..cb918a0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3398,7 +3398,8 @@
         // Check if we should mark the processrecord for first launch after force-stopping
         if (wasStopped) {
             boolean wasEverLaunched = false;
-            if (android.app.Flags.useAppInfoNotLaunched()) {
+            if (android.app.Flags.useAppInfoNotLaunched()
+                    || mService.mConstants.mFlagUseAppInfoNotLaunched) {
                 wasEverLaunched = !info.isNotLaunched();
             } else {
                 try {
@@ -3419,7 +3420,8 @@
                         : STOPPED_STATE_FIRST_LAUNCH;
                 r.getWindowProcessController().setStoppedState(stoppedState);
             } else {
-                if (android.app.Flags.useAppInfoNotLaunched()) {
+                if (android.app.Flags.useAppInfoNotLaunched()
+                        || mService.mConstants.mFlagUseAppInfoNotLaunched) {
                     // If it was launched before, then it must be a force-stop
                     r.setWasForceStopped(wasEverLaunched);
                 } else {
@@ -3769,7 +3771,7 @@
                     boolean hasActivity = false;
                     int connUid = 0;
                     int connGroup = 0;
-                    while (i >= bottomI) {
+                    while (subProc.info.uid != uid) {
                         mLruProcesses.remove(i);
                         mLruProcesses.add(endIndex, subProc);
                         if (DEBUG_LRU) Slog.d(TAG_LRU,
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 439bca0..a13ce65 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -370,6 +370,13 @@
                   String propertyName = "next_boot." + makeAconfigFlagPropertyName(
                       actualNamespace, actualFlagName);
 
+                  if (Flags.supportLocalOverridesSysprops()) {
+                    // Don't propagate if there is a local override.
+                    String overrideName = actualNamespace + ":" + actualFlagName;
+                    if (DeviceConfig.getProperty(NAMESPACE_LOCAL_OVERRIDES, overrideName) != null) {
+                      continue;
+                    }
+                  }
                   setProperty(propertyName, flagValue);
               }
 
@@ -388,6 +395,42 @@
                 if (enableAconfigStorageDaemon()) {
                     setLocalOverridesInNewStorage(properties);
                 }
+
+                if (Flags.supportLocalOverridesSysprops()) {
+                  String overridesNamespace = properties.getNamespace();
+                  for (String key : properties.getKeyset()) {
+                    String realNamespace = key.split(":")[0];
+                    String realFlagName = key.split(":")[1];
+                    String aconfigPropertyName =
+                        makeAconfigFlagPropertyName(realNamespace, realFlagName);
+                    if (aconfigPropertyName == null) {
+                      logErr("unable to construct system property for " + realNamespace + "/"
+                        + key);
+                      return;
+                    }
+
+                    if (properties.getString(key, null) == null) {
+                      String deviceConfigValue =
+                              DeviceConfig.getProperty(realNamespace, realFlagName);
+                      String stagedDeviceConfigValue =
+                              DeviceConfig.getProperty(NAMESPACE_REBOOT_STAGING,
+                                              realNamespace + "*" + realFlagName);
+
+                      setProperty(aconfigPropertyName, deviceConfigValue);
+                      if (stagedDeviceConfigValue == null) {
+                        setProperty("next_boot." + aconfigPropertyName, deviceConfigValue);
+                      } else {
+                        setProperty("next_boot." + aconfigPropertyName, stagedDeviceConfigValue);
+                      }
+                    } else {
+                      // Otherwise, propagate the override to sysprops.
+                      setProperty(aconfigPropertyName, properties.getString(key, null));
+                      // If there's a staged value, make sure it's the override value.
+                      setProperty("next_boot." + aconfigPropertyName,
+                                properties.getString(key, null));
+                    }
+                  }
+                }
         });
     }
 
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 6e8eb7d..ab5e2d0 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -94,12 +94,7 @@
   ],
   "postsubmit": [
     {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.am."
-        }
-      ]
+      "name": "FrameworksServicesTests_android_server_am"
     },
     {
       "name": "CtsAppDataIsolationHostTestCases"
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 430be03..314664b 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -110,7 +110,8 @@
 
         mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                 parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
-                AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
+                AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
+                DiscreteRegistry.ACCESS_TYPE_NOTE_OP);
     }
 
     /**
@@ -254,7 +255,7 @@
         if (isStarted) {
             mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
-                    attributionFlags, attributionChainId);
+                    attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP);
         }
     }
 
@@ -290,12 +291,17 @@
      * stopping in the HistoricalRegistry, but does not delete it.
      *
      * @param triggeredByUidStateChange If {@code true}, then this method operates as usual, except
-     * that {@link AppOpsService#mActiveWatchers} will not be notified. This is currently only
-     * used in {@link #onUidStateChanged(int)}, for the purpose of restarting (i.e.,
-     * finishing then immediately starting again in the new uid state) the AttributedOp. In this
-     * case, the caller is responsible for guaranteeing that either the AttributedOp is started
-     * again or all {@link AppOpsService#mActiveWatchers} are notified that the AttributedOp is
-     * finished.
+     *                                  that {@link AppOpsService#mActiveWatchers} will not be
+     *                                  notified. This is currently only
+     *                                  used in {@link #onUidStateChanged(int)}, for the purpose of
+     *                                  restarting (i.e.,
+     *                                  finishing then immediately starting again in the new uid
+     *                                  state) the AttributedOp. In this
+     *                                  case, the caller is responsible for guaranteeing that either
+     *                                  the AttributedOp is started
+     *                                  again or all {@link AppOpsService#mActiveWatchers} are
+     *                                  notified that the AttributedOp is
+     *                                  finished.
      */
     @SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
     private void finishOrPause(@NonNull IBinder clientId, boolean triggeredByUidStateChange,
@@ -335,7 +341,9 @@
             mAppOpsService.mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, event.getUidState(),
                     event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration(),
-                    event.getAttributionFlags(), event.getAttributionChainId());
+                    event.getAttributionFlags(), event.getAttributionChainId(),
+                    isPausing ? DiscreteRegistry.ACCESS_TYPE_PAUSE_OP
+                            : DiscreteRegistry.ACCESS_TYPE_FINISH_OP);
 
             if (!isPausing) {
                 mAppOpsService.mInProgressStartOpEventPool.release(event);
@@ -443,7 +451,7 @@
             mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, event.getUidState(),
                     event.getFlags(), startTime, event.getAttributionFlags(),
-                    event.getAttributionChainId());
+                    event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP);
             if (shouldSendActive) {
                 mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                         parent.packageName, tag, event.getVirtualDeviceId(), true,
@@ -864,12 +872,12 @@
         }
 
         InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
-                @Nullable String attributionTag, int virtualDeviceId,  @NonNull Runnable onDeath,
+                @Nullable String attributionTag, int virtualDeviceId, @NonNull Runnable onDeath,
                 int proxyUid, @Nullable String proxyPackageName,
                 @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
-                @AppOpsManager.UidState int uidState,
-                @AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags
-                int attributionFlags, int attributionChainId) throws RemoteException {
+                @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
+                @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId)
+                throws RemoteException {
 
             InProgressStartOpEvent recycled = acquire();
 
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 2ce4623..7f161f6 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -32,13 +32,23 @@
 import static android.app.AppOpsManager.OP_FLAG_SELF;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
 import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
+import static android.app.AppOpsManager.OP_PROCESS_OUTGOING_CALLS;
+import static android.app.AppOpsManager.OP_READ_ICC_SMS;
+import static android.app.AppOpsManager.OP_READ_SMS;
 import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
 import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OP_RESERVED_FOR_TESTING;
+import static android.app.AppOpsManager.OP_SEND_SMS;
+import static android.app.AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS;
+import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import static android.app.AppOpsManager.OP_WRITE_ICC_SMS;
+import static android.app.AppOpsManager.OP_WRITE_SMS;
 import static android.app.AppOpsManager.flagsToString;
 import static android.app.AppOpsManager.getUidStateName;
 import static android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
@@ -46,6 +56,7 @@
 import static java.lang.Long.min;
 import static java.lang.Math.max;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
@@ -62,6 +73,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -72,6 +84,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
 import java.time.Duration;
 import java.time.Instant;
@@ -125,7 +139,6 @@
  * relies on {@link HistoricalRegistry} for controlling that no calls are allowed until then. All
  * outside calls are going through {@link HistoricalRegistry}, where
  * {@link HistoricalRegistry#isPersistenceInitializedMLocked()} check is done.
- *
  */
 
 final class DiscreteRegistry {
@@ -142,11 +155,40 @@
             + OP_PHONE_CALL_MICROPHONE + "," + OP_PHONE_CALL_CAMERA + ","
             + OP_RECEIVE_AMBIENT_TRIGGER_AUDIO + "," + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
             + "," + OP_RESERVED_FOR_TESTING;
+    private static final int[] sDiscreteOpsToLog =
+            new int[]{OP_FINE_LOCATION, OP_COARSE_LOCATION, OP_EMERGENCY_LOCATION, OP_CAMERA,
+                    OP_RECORD_AUDIO, OP_PHONE_CALL_MICROPHONE, OP_PHONE_CALL_CAMERA,
+                    OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, OP_READ_SMS,
+                    OP_WRITE_SMS, OP_SEND_SMS, OP_READ_ICC_SMS, OP_WRITE_ICC_SMS,
+                    OP_SMS_FINANCIAL_TRANSACTIONS, OP_SYSTEM_ALERT_WINDOW, OP_MONITOR_LOCATION,
+                    OP_MONITOR_HIGH_POWER_LOCATION, OP_PROCESS_OUTGOING_CALLS,
+            };
     private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
     private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
     private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION =
             Duration.ofMinutes(1).toMillis();
 
+    static final int ACCESS_TYPE_NOTE_OP =
+            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__NOTE_OP;
+    static final int ACCESS_TYPE_START_OP =
+            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__START_OP;
+    static final int ACCESS_TYPE_FINISH_OP =
+            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__FINISH_OP;
+    static final int ACCESS_TYPE_PAUSE_OP =
+            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__PAUSE_OP;
+    static final int ACCESS_TYPE_RESUME_OP =
+            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__RESUME_OP;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"ACCESS_TYPE_"}, value = {
+            ACCESS_TYPE_NOTE_OP,
+            ACCESS_TYPE_START_OP,
+            ACCESS_TYPE_FINISH_OP,
+            ACCESS_TYPE_PAUSE_OP,
+            ACCESS_TYPE_RESUME_OP
+    })
+    public @interface AccessType {}
+
     private static long sDiscreteHistoryCutoff;
     private static long sDiscreteHistoryQuantization;
     private static int[] sDiscreteOps;
@@ -255,7 +297,23 @@
     void recordDiscreteAccess(int uid, String packageName, @NonNull String deviceId, int op,
             @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
             @AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
-            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
+            @AccessType int accessType) {
+        if (shouldLogAccess(op)) {
+            int firstChar = 0;
+            if (attributionTag != null && attributionTag.startsWith(packageName)) {
+                firstChar = packageName.length();
+                if (firstChar < attributionTag.length() && attributionTag.charAt(firstChar)
+                        == '.') {
+                    firstChar++;
+                }
+            }
+            FrameworkStatsLog.write(FrameworkStatsLog.APP_OP_ACCESS_TRACKED, uid, op, accessType,
+                    uidState, flags, attributionFlags,
+                    attributionTag == null ? null : attributionTag.substring(firstChar),
+                    attributionChainId);
+        }
+
         if (!isDiscreteOp(op, flags)) {
             return;
         }
@@ -388,7 +446,7 @@
                                 if (event == null
                                         || event.mAttributionChainId == ATTRIBUTION_CHAIN_ID_NONE
                                         || (event.mAttributionFlags & ATTRIBUTION_FLAG_TRUSTED)
-                                                == 0) {
+                                        == 0) {
                                     continue;
                                 }
 
@@ -1523,6 +1581,11 @@
         return true;
     }
 
+    private static boolean shouldLogAccess(int op) {
+        return Flags.appopAccessTrackingLoggingEnabled()
+                && ArrayUtils.contains(sDiscreteOpsToLog, op);
+    }
+
     private static long discretizeTimeStamp(long timeStamp) {
         return timeStamp / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;
 
@@ -1530,7 +1593,7 @@
 
     private static long discretizeDuration(long duration) {
         return duration == -1 ? -1 : (duration + sDiscreteHistoryQuantization - 1)
-                        / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;
+                / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;
     }
 
     void setDebugMode(boolean debugMode) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index fffb108..6b02538 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -474,7 +474,8 @@
     void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
             @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
             @OpFlags int flags, long accessTime,
-            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
+            @DiscreteRegistry.AccessType int accessType) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -487,7 +488,7 @@
 
                 mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                         attributionTag, flags, uidState, accessTime, -1, attributionFlags,
-                        attributionChainId);
+                        attributionChainId, accessType);
             }
         }
     }
@@ -510,7 +511,8 @@
     void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
             @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
             @OpFlags int flags, long eventStartTime, long increment,
-            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
+            @DiscreteRegistry.AccessType int accessType) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -522,7 +524,7 @@
                         attributionTag, uidState, flags, increment);
                 mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                         attributionTag, flags, uidState, eventStartTime, increment,
-                        attributionFlags, attributionChainId);
+                        attributionFlags, attributionChainId, accessType);
             }
         }
     }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6daf0d0..c3d09bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9211,7 +9211,7 @@
                 index = 1;
             }
 
-            if (replaceStreamBtSco()) {
+            if (replaceStreamBtSco() && index != 0) {
                 index = (int) (mIndexMin + (index * 10 - mIndexMin) / getIndexStepFactor() + 5)
                         / 10;
             }
diff --git a/services/core/java/com/android/server/biometrics/biometrics.aconfig b/services/core/java/com/android/server/biometrics/biometrics.aconfig
index b2e95aa..d3da8dd 100644
--- a/services/core/java/com/android/server/biometrics/biometrics.aconfig
+++ b/services/core/java/com/android/server/biometrics/biometrics.aconfig
@@ -24,3 +24,13 @@
       purpose: PURPOSE_BUGFIX
   }
 }
+
+flag {
+  name: "set_ignore_speed_up"
+  namespace: "biometrics_framework"
+  description: "This flag controls whether setIgnoreDisplayTouches is called directly on session from FingerprintProvider"
+  bug: "359289274"
+  metadata {
+      purpose: PURPOSE_BUGFIX
+  }
+}
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 8195efe..456591c 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
@@ -791,7 +791,17 @@
 
     @Override
     public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) {
-        mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+        if (Flags.setIgnoreSpeedUp()) {
+            try {
+                mFingerprintSensors.get(
+                        sensorId).getLazySession().get().getSession().setIgnoreDisplayTouches(
+                        ignoreTouches);
+                Slog.d(getTag(), "setIgnoreDisplayTouches set to " + ignoreTouches);
+            } catch (Exception e) {
+                Slog.w(getTag(), "setIgnore failed", e);
+            }
+        } else {
+            mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
                 requestId, (client) -> {
                     if (!(client instanceof Udfps)) {
                         Slog.e(getTag(),
@@ -800,6 +810,7 @@
                     }
                     ((Udfps) client).setIgnoreDisplayTouches(ignoreTouches);
                 });
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index d78fdfa..dc263c5 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -796,7 +796,6 @@
     private DensityMapping mDensityMapping;
     private String mLoadedFrom = null;
 
-
     // Represents the auto-brightness brightening light debounce.
     private long mAutoBrightnessBrighteningLightDebounce =
             INVALID_AUTO_BRIGHTNESS_LIGHT_DEBOUNCE;
@@ -1686,7 +1685,6 @@
                 + "\n"
                 + "mLuxThrottlingData=" + mLuxThrottlingData
                 + ", mHbmData=" + mHbmData
-
                 + ", mThermalBrightnessThrottlingDataMapByThrottlingId="
                 + mThermalBrightnessThrottlingDataMapByThrottlingId
                 + "\n"
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 9644b1d..3c2167e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -4779,6 +4779,18 @@
                     token, displayId, modeIds);
         }
 
+        @Override // Binder call
+        public float getHighestHdrSdrRatio(int displayId) {
+            DisplayDeviceConfig ddc =
+                    mDisplayDeviceConfigProvider.getDisplayDeviceConfig(displayId);
+            if (ddc == null) {
+                throw new IllegalArgumentException(
+                        "Display ID does not have a config: " + displayId);
+            }
+            return ddc.getHdrBrightnessData() != null
+                    ? ddc.getHdrBrightnessData().highestHdrSdrRatio : 1;
+        }
+
         @EnforcePermission(android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS)
         @Override // Binder call
         public float[] getDozeBrightnessSensorValueToBrightness(int displayId) {
diff --git a/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java b/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
index 5b4e8d5..a60434b 100644
--- a/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
+++ b/services/core/java/com/android/server/display/config/DisplayDeviceConfigUtils.java
@@ -60,4 +60,23 @@
 
         return Spline.createSpline(x, y);
     }
+
+    /**
+     * Get the highest HDR/SDR ratio from the given map.
+     * @param points The map of brightness values to HDR/SDR ratios
+     * @param extractor Used to retrieve the ratio from the map element
+     * @return The highest HDR/SDR ratio
+     * @param <T> The type of the map elements
+     */
+    public static <T> float getHighestHdrSdrRatio(List<T> points,
+            Function<T, BigDecimal> extractor) {
+        float highestRatio = 1;
+        for (T point : points) {
+            float ratio = extractor.apply(point).floatValue();
+            if (ratio > highestRatio) {
+                highestRatio = ratio;
+            }
+        }
+        return highestRatio;
+    }
 }
diff --git a/services/core/java/com/android/server/display/config/HdrBrightnessData.java b/services/core/java/com/android/server/display/config/HdrBrightnessData.java
index ef4a798..751ab30 100644
--- a/services/core/java/com/android/server/display/config/HdrBrightnessData.java
+++ b/services/core/java/com/android/server/display/config/HdrBrightnessData.java
@@ -126,13 +126,16 @@
     @Nullable
     public final Spline sdrToHdrRatioSpline;
 
+    public final float highestHdrSdrRatio;
+
     @VisibleForTesting
     public HdrBrightnessData(Map<Float, Float> maxBrightnessLimits,
             long brightnessIncreaseDebounceMillis, float screenBrightnessRampIncrease,
             long brightnessDecreaseDebounceMillis, float screenBrightnessRampDecrease,
             float hbmTransitionPoint,
             float minimumHdrPercentOfScreenForNbm, float minimumHdrPercentOfScreenForHbm,
-            boolean allowInLowPowerMode, @Nullable Spline sdrToHdrRatioSpline) {
+            boolean allowInLowPowerMode, @Nullable Spline sdrToHdrRatioSpline,
+            float highestHdrSdrRatio) {
         this.maxBrightnessLimits = maxBrightnessLimits;
         this.brightnessIncreaseDebounceMillis = brightnessIncreaseDebounceMillis;
         this.screenBrightnessRampIncrease = screenBrightnessRampIncrease;
@@ -143,6 +146,7 @@
         this.minimumHdrPercentOfScreenForHbm = minimumHdrPercentOfScreenForHbm;
         this.allowInLowPowerMode = allowInLowPowerMode;
         this.sdrToHdrRatioSpline = sdrToHdrRatioSpline;
+        this.highestHdrSdrRatio = highestHdrSdrRatio;
     }
 
     @Override
@@ -158,6 +162,7 @@
                 + ", minimumHdrPercentOfScreenForHbm: " + minimumHdrPercentOfScreenForHbm
                 + ", allowInLowPowerMode: " + allowInLowPowerMode
                 + ", sdrToHdrRatioSpline: " + sdrToHdrRatioSpline
+                + ", highestHdrSdrRatio: " + highestHdrSdrRatio
                 + "} ";
     }
 
@@ -198,7 +203,9 @@
                 hdrConfig.getScreenBrightnessRampDecrease().floatValue(),
                 getTransitionPoint(hbmConfig, transitionPointProvider),
                 minHdrPercentForNbm, minHdrPercentForHbm, hdrConfig.getAllowInLowPowerMode(),
-                getSdrHdrRatioSpline(hdrConfig, config.getHighBrightnessMode()));
+                getSdrHdrRatioSpline(hdrConfig, config.getHighBrightnessMode()),
+                getHighestSdrHdrRatio(hdrConfig, config.getHighBrightnessMode())
+                );
     }
 
     private static float getTransitionPoint(@Nullable HighBrightnessMode hbm,
@@ -222,7 +229,8 @@
                 0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
                 0, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET,
                 getTransitionPoint(hbm, transitionPointProvider),
-                fallbackPercent, fallbackPercent, false, fallbackSpline);
+                fallbackPercent, fallbackPercent, false, fallbackSpline,
+                getFallbackHighestSdrHdrRatio(hbm));
     }
 
     private static float getFallbackHdrPercent(HighBrightnessMode hbm) {
@@ -251,4 +259,23 @@
         return DisplayDeviceConfigUtils.createSpline(fallbackMap.getPoint(),
                 SdrHdrRatioPoint::getSdrNits, SdrHdrRatioPoint::getHdrRatio);
     }
+
+    private static float getHighestSdrHdrRatio(HdrBrightnessConfig hdrConfig,
+            HighBrightnessMode hbm) {
+        NonNegativeFloatToFloatMap sdrHdrRatioMap = hdrConfig.getSdrHdrRatioMap();
+        if (sdrHdrRatioMap == null) {
+            return getFallbackHighestSdrHdrRatio(hbm);
+        }
+        return DisplayDeviceConfigUtils.getHighestHdrSdrRatio(sdrHdrRatioMap.getPoint(),
+                NonNegativeFloatToFloatPoint::getSecond);
+    }
+
+    private static float getFallbackHighestSdrHdrRatio(HighBrightnessMode hbm) {
+        SdrHdrRatioMap fallbackMap = hbm != null ? hbm.getSdrHdrRatioMap_all() : null;
+        if (fallbackMap == null) {
+            return 1;
+        }
+        return DisplayDeviceConfigUtils.getHighestHdrSdrRatio(fallbackMap.getPoint(),
+                SdrHdrRatioPoint::getHdrRatio);
+    }
 }
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index da5063a..70230b4 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -246,6 +246,14 @@
 }
 
 flag {
+    name: "highest_hdr_sdr_ratio_api"
+    namespace: "display_manager"
+    description: "Feature flag for an API to get the highest defined HDR/SDR ratio for a display."
+    bug: "335181559"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "doze_brightness_float"
     namespace: "display_manager"
     description: "Define doze brightness in the float scale [0, 1]."
diff --git a/services/core/java/com/android/server/hdmi/TEST_MAPPING b/services/core/java/com/android/server/hdmi/TEST_MAPPING
index 1c85c7f..d116087d 100644
--- a/services/core/java/com/android/server/hdmi/TEST_MAPPING
+++ b/services/core/java/com/android/server/hdmi/TEST_MAPPING
@@ -6,15 +6,7 @@
   ],
   "postsubmit": [
     {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.hdmi"
-        },
-        {
-          "exclude-annotation": "org.junit.Ignore"
-        }
-      ]
+      "name": "FrameworksServicesTests_android_server_hdmi"
     }
   ],
   // Postsubmit tests for TV devices
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index dfcea9f..ca8ae6e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -52,6 +52,7 @@
 import android.hardware.input.IInputManager;
 import android.hardware.input.IInputSensorEventListener;
 import android.hardware.input.IKeyGestureEventListener;
+import android.hardware.input.IKeyGestureHandler;
 import android.hardware.input.IKeyboardBacklightListener;
 import android.hardware.input.IStickyModifierStateListener;
 import android.hardware.input.ITabletModeChangedListener;
@@ -164,7 +165,6 @@
     private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
     private static final int MSG_RELOAD_DEVICE_ALIASES = 2;
     private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 3;
-    private static final int MSG_KEY_GESTURE_COMPLETED = 4;
 
     private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
     private static final AdditionalDisplayInputProperties
@@ -476,7 +476,7 @@
                         injector.getLooper(), injector.getUEventManager())
                 : new KeyboardBacklightControllerInterface() {};
         mStickyModifierStateController = new StickyModifierStateController();
-        mKeyGestureController = new KeyGestureController();
+        mKeyGestureController = new KeyGestureController(mContext, injector.getLooper());
         mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(),
                 mNative);
         mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
@@ -2458,6 +2458,11 @@
     // Native callback.
     @SuppressWarnings("unused")
     private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+        // TODO(b/358569822): Move shortcut trigger logic from PWM to KeyGestureController
+        long value = mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags);
+        if (value != 0) { // If key is consumed (i.e. non-zero value)
+            return value;
+        }
         return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
     }
 
@@ -2763,33 +2768,38 @@
 
     @Override
     @PermissionManuallyEnforced
-    public void registerKeyGestureEventListener(
-            @NonNull IKeyGestureEventListener listener) {
+    public void registerKeyGestureEventListener(@NonNull IKeyGestureEventListener listener) {
         enforceManageKeyGesturePermission();
 
         Objects.requireNonNull(listener);
-        mKeyGestureController.registerKeyGestureEventListener(listener,
-                Binder.getCallingPid());
+        mKeyGestureController.registerKeyGestureEventListener(listener, Binder.getCallingPid());
     }
 
     @Override
     @PermissionManuallyEnforced
-    public void unregisterKeyGestureEventListener(
-            @NonNull IKeyGestureEventListener listener) {
+    public void unregisterKeyGestureEventListener(@NonNull IKeyGestureEventListener listener) {
         enforceManageKeyGesturePermission();
 
         Objects.requireNonNull(listener);
-        mKeyGestureController.unregisterKeyGestureEventListener(listener,
-                Binder.getCallingPid());
+        mKeyGestureController.unregisterKeyGestureEventListener(listener, Binder.getCallingPid());
     }
 
-    private void handleKeyGestureCompleted(KeyGestureEvent event) {
-        InputDevice device = getInputDevice(event.getDeviceId());
-        if (device == null || device.isVirtual()) {
-            return;
-        }
-        KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event);
-        mKeyGestureController.onKeyGestureEvent(event);
+    @Override
+    @PermissionManuallyEnforced
+    public void registerKeyGestureHandler(@NonNull IKeyGestureHandler handler) {
+        enforceManageKeyGesturePermission();
+
+        Objects.requireNonNull(handler);
+        mKeyGestureController.registerKeyGestureHandler(handler, Binder.getCallingPid());
+    }
+
+    @Override
+    @PermissionManuallyEnforced
+    public void unregisterKeyGestureHandler(@NonNull IKeyGestureHandler handler) {
+        enforceManageKeyGesturePermission();
+
+        Objects.requireNonNull(handler);
+        mKeyGestureController.unregisterKeyGestureHandler(handler, Binder.getCallingPid());
     }
 
     /**
@@ -2960,9 +2970,6 @@
                     boolean inTabletMode = (boolean) args.arg1;
                     deliverTabletModeChanged(whenNanos, inTabletMode);
                     break;
-                case MSG_KEY_GESTURE_COMPLETED:
-                    KeyGestureEvent event = (KeyGestureEvent) msg.obj;
-                    handleKeyGestureCompleted(event);
             }
         }
     }
@@ -3292,9 +3299,8 @@
         @Override
         public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
                 @KeyGestureEvent.KeyGestureType int gestureType) {
-            mHandler.obtainMessage(MSG_KEY_GESTURE_COMPLETED,
-                    new KeyGestureEvent(deviceId, keycodes, modifierState,
-                            gestureType)).sendToTarget();
+            mKeyGestureController.notifyKeyGestureCompleted(deviceId, keycodes, modifierState,
+                    gestureType);
         }
     }
 
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 674d3c4..bfdb1c1 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -17,15 +17,32 @@
 package com.android.server.input;
 
 import android.annotation.BinderThread;
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.input.AidlKeyGestureEvent;
 import android.hardware.input.IKeyGestureEventListener;
+import android.hardware.input.IKeyGestureHandler;
+import android.hardware.input.InputManager;
 import android.hardware.input.KeyGestureEvent;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
+import android.view.InputDevice;
+import android.view.KeyEvent;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.TreeMap;
 
 /**
  * A thread-safe component of {@link InputManagerService} responsible for managing callbacks when a
@@ -39,12 +56,101 @@
     // 'adb shell setprop log.tag.KeyGestureController DEBUG' (requires restart)
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final int mSystemPid;
+
     // List of currently registered key gesture event listeners keyed by process pid
     @GuardedBy("mKeyGestureEventListenerRecords")
     private final SparseArray<KeyGestureEventListenerRecord>
             mKeyGestureEventListenerRecords = new SparseArray<>();
 
-    public void onKeyGestureEvent(KeyGestureEvent event) {
+    // List of currently registered key gesture event handler keyed by process pid. The map sorts
+    // in the order of preference of the handlers, and we prioritize handlers in system server
+    // over external handlers..
+    @GuardedBy("mKeyGestureHandlerRecords")
+    private final TreeMap<Integer, KeyGestureHandlerRecord> mKeyGestureHandlerRecords;
+
+    KeyGestureController(Context context, Looper looper) {
+        mContext = context;
+        mHandler = new Handler(looper, this::handleMessage);
+        mSystemPid = Process.myPid();
+        mKeyGestureHandlerRecords = new TreeMap<>((p1, p2) -> {
+            if (Objects.equals(p1, p2)) {
+                return 0;
+            }
+            if (p1 == mSystemPid) {
+                return -1;
+            } else if (p2 == mSystemPid) {
+                return 1;
+            } else {
+                return Integer.compare(p1, p2);
+            }
+        });
+    }
+
+    public int interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+        // TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate
+        //  KeyGestureHandler (PWM is one of the handlers)
+        return 0;
+    }
+
+    @VisibleForTesting
+    boolean handleKeyGesture(int deviceId, int[] keycodes, int modifierState,
+            @KeyGestureEvent.KeyGestureType int gestureType, int action, int displayId,
+            IBinder focusedToken, int flags) {
+        AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes,
+                modifierState, gestureType, action, displayId, flags);
+        synchronized (mKeyGestureHandlerRecords) {
+            for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
+                if (handler.handleKeyGesture(event, focusedToken)) {
+                    Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT, event);
+                    mHandler.sendMessage(msg);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
+        synchronized (mKeyGestureHandlerRecords) {
+            for (KeyGestureHandlerRecord handler : mKeyGestureHandlerRecords.values()) {
+                if (handler.isKeyGestureSupported(gestureType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
+            @KeyGestureEvent.KeyGestureType int gestureType) {
+        // TODO(b/358569822): Once we move the gesture detection logic to IMS, we ideally
+        //  should not rely on PWM to tell us about the gesture start and end.
+        AidlKeyGestureEvent event = createKeyGestureEvent(deviceId, keycodes, modifierState,
+                gestureType, KeyGestureEvent.ACTION_GESTURE_COMPLETE, Display.DEFAULT_DISPLAY, 0);
+        mHandler.obtainMessage(MSG_NOTIFY_KEY_GESTURE_EVENT, event).sendToTarget();
+    }
+
+    @MainThread
+    private void notifyKeyGestureEvent(AidlKeyGestureEvent event) {
+        InputDevice device = getInputDevice(event.deviceId);
+        if (device == null || device.isVirtual()) {
+            return;
+        }
+        if (event.action == KeyGestureEvent.ACTION_GESTURE_COMPLETE) {
+            KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event.keycodes,
+                    event.modifierState,
+                    KeyGestureEvent.keyGestureTypeToLogEvent(event.gestureType));
+        }
+        notifyAllListeners(event);
+    }
+
+    @MainThread
+    private void notifyAllListeners(AidlKeyGestureEvent event) {
         if (DEBUG) {
             Slog.d(TAG, "Key gesture event occurred, event = " + event);
         }
@@ -56,17 +162,26 @@
         }
     }
 
+    @MainThread
+    private boolean handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_NOTIFY_KEY_GESTURE_EVENT:
+                AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj;
+                notifyKeyGestureEvent(event);
+                break;
+        }
+        return true;
+    }
+
     /** Register the key gesture event listener for a process. */
     @BinderThread
-    public void registerKeyGestureEventListener(IKeyGestureEventListener listener,
-            int pid) {
+    public void registerKeyGestureEventListener(IKeyGestureEventListener listener, int pid) {
         synchronized (mKeyGestureEventListenerRecords) {
             if (mKeyGestureEventListenerRecords.get(pid) != null) {
                 throw new IllegalStateException("The calling process has already registered "
                         + "a KeyGestureEventListener.");
             }
-            KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord(
-                    pid, listener);
+            KeyGestureEventListenerRecord record = new KeyGestureEventListenerRecord(pid, listener);
             try {
                 listener.asBinder().linkToDeath(record, 0);
             } catch (RemoteException ex) {
@@ -78,8 +193,7 @@
 
     /** Unregister the key gesture event listener for a process. */
     @BinderThread
-    public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener,
-            int pid) {
+    public void unregisterKeyGestureEventListener(IKeyGestureEventListener listener, int pid) {
         synchronized (mKeyGestureEventListenerRecords) {
             KeyGestureEventListenerRecord record =
                     mKeyGestureEventListenerRecords.get(pid);
@@ -120,10 +234,9 @@
             onKeyGestureEventListenerDied(mPid);
         }
 
-        public void onKeyGestureEvent(KeyGestureEvent event) {
+        public void onKeyGestureEvent(AidlKeyGestureEvent event) {
             try {
-                mListener.onKeyGestureEvent(event.getDeviceId(), event.getKeycodes(),
-                        event.getModifierState(), event.getKeyGestureType());
+                mListener.onKeyGestureEvent(event);
             } catch (RemoteException ex) {
                 Slog.w(TAG, "Failed to notify process " + mPid
                         + " that key gesture event occurred, assuming it died.", ex);
@@ -131,4 +244,107 @@
             }
         }
     }
+
+    /** Register the key gesture event handler for a process. */
+    @BinderThread
+    public void registerKeyGestureHandler(IKeyGestureHandler handler, int pid) {
+        synchronized (mKeyGestureHandlerRecords) {
+            if (mKeyGestureHandlerRecords.get(pid) != null) {
+                throw new IllegalStateException("The calling process has already registered "
+                        + "a KeyGestureHandler.");
+            }
+            KeyGestureHandlerRecord record = new KeyGestureHandlerRecord(pid, handler);
+            try {
+                handler.asBinder().linkToDeath(record, 0);
+            } catch (RemoteException ex) {
+                throw new RuntimeException(ex);
+            }
+            mKeyGestureHandlerRecords.put(pid, record);
+        }
+    }
+
+    /** Unregister the key gesture event handler for a process. */
+    @BinderThread
+    public void unregisterKeyGestureHandler(IKeyGestureHandler handler, int pid) {
+        synchronized (mKeyGestureHandlerRecords) {
+            KeyGestureHandlerRecord record = mKeyGestureHandlerRecords.get(pid);
+            if (record == null) {
+                throw new IllegalStateException("The calling process has no registered "
+                        + "KeyGestureHandler.");
+            }
+            if (record.mKeyGestureHandler.asBinder() != handler.asBinder()) {
+                throw new IllegalStateException("The calling process has a different registered "
+                        + "KeyGestureHandler.");
+            }
+            record.mKeyGestureHandler.asBinder().unlinkToDeath(record, 0);
+            mKeyGestureHandlerRecords.remove(pid);
+        }
+    }
+
+    private void onKeyGestureHandlerDied(int pid) {
+        synchronized (mKeyGestureHandlerRecords) {
+            mKeyGestureHandlerRecords.remove(pid);
+        }
+    }
+
+    // A record of a registered key gesture event listener from one process.
+    private class KeyGestureHandlerRecord implements IBinder.DeathRecipient {
+        public final int mPid;
+        public final IKeyGestureHandler mKeyGestureHandler;
+
+        KeyGestureHandlerRecord(int pid, IKeyGestureHandler keyGestureHandler) {
+            mPid = pid;
+            mKeyGestureHandler = keyGestureHandler;
+        }
+
+        @Override
+        public void binderDied() {
+            if (DEBUG) {
+                Slog.d(TAG, "Key gesture event handler for pid " + mPid + " died.");
+            }
+            onKeyGestureHandlerDied(mPid);
+        }
+
+        public boolean handleKeyGesture(AidlKeyGestureEvent event, IBinder focusedToken) {
+            try {
+                return mKeyGestureHandler.handleKeyGesture(event, focusedToken);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to send key gesture to process " + mPid
+                        + ", assuming it died.", ex);
+                binderDied();
+            }
+            return false;
+        }
+
+        public boolean isKeyGestureSupported(@KeyGestureEvent.KeyGestureType int gestureType) {
+            try {
+                return mKeyGestureHandler.isKeyGestureSupported(gestureType);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to identify if key gesture type is supported by the "
+                        + "process " + mPid + ", assuming it died.", ex);
+                binderDied();
+            }
+            return false;
+        }
+    }
+
+    @Nullable
+    private InputDevice getInputDevice(int deviceId) {
+        InputManager inputManager = mContext.getSystemService(InputManager.class);
+        return inputManager != null ? inputManager.getInputDevice(deviceId) : null;
+    }
+
+    private AidlKeyGestureEvent createKeyGestureEvent(int deviceId, int[] keycodes,
+            int modifierState, @KeyGestureEvent.KeyGestureType int gestureType, int action,
+            int displayId, int flags) {
+        AidlKeyGestureEvent event = new AidlKeyGestureEvent();
+        event.deviceId = deviceId;
+        event.keycodes = keycodes;
+        event.modifierState = modifierState;
+        event.gestureType = gestureType;
+        event.action = action;
+        event.displayId = displayId;
+        event.flags = flags;
+        return event;
+    }
 }
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
index 1daf4db..609164a4 100644
--- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -24,7 +24,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.hardware.input.KeyGestureEvent;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria;
 import android.icu.util.ULocale;
@@ -41,6 +40,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -60,23 +60,26 @@
     @VisibleForTesting
     public static final String DEFAULT_LANGUAGE_TAG = "None";
 
+    private static final int INVALID_SYSTEMS_EVENT = FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
+
     /**
      * Log keyboard system shortcuts for the proto
      * {@link com.android.os.input.KeyboardSystemsEventReported}
      * defined in "stats/atoms/input/input_extension_atoms.proto"
      */
     public static void logKeyboardSystemsEventReportedAtom(@NonNull InputDevice inputDevice,
-            @NonNull KeyGestureEvent keyGestureEvent) {
-        if (inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
+            int[] keycodes, int modifierState, int systemsEvent) {
+        if (systemsEvent == INVALID_SYSTEMS_EVENT || inputDevice.isVirtual()
+                || !inputDevice.isFullKeyboard()) {
             return;
         }
         FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
                 inputDevice.getVendorId(), inputDevice.getProductId(),
-                keyGestureEvent.getKeyGestureType(), keyGestureEvent.getKeycodes(),
-                keyGestureEvent.getModifierState(), inputDevice.getDeviceBus());
+                systemsEvent, keycodes, modifierState, inputDevice.getDeviceBus());
 
         if (DEBUG) {
-            Slog.d(TAG, "Logging Keyboard system event: " + keyGestureEvent);
+            Slog.d(TAG, "Logging Keyboard system event: " + modifierState + " + " + Arrays.toString(
+                    keycodes) + " -> " + systemsEvent);
         }
     }
 
diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
index 486d4af..cc13e8e 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
@@ -16,6 +16,8 @@
 
 package com.android.server.input.debug;
 
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -24,6 +26,7 @@
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
 import android.util.Slog;
+import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -38,6 +41,13 @@
 import java.util.Objects;
 
 public class TouchpadDebugView extends LinearLayout {
+    private static final float MAX_SCREEN_WIDTH_PROPORTION = 0.4f;
+    private static final float MAX_SCREEN_HEIGHT_PROPORTION = 0.4f;
+    private static final float MIN_SCALE_FACTOR = 10f;
+    private static final float TEXT_SIZE_SP = 16.0f;
+    private static final float DEFAULT_RES_X = 47f;
+    private static final float DEFAULT_RES_Y = 45f;
+
     /**
      * Input device ID for the touchpad that this debug view is displaying.
      */
@@ -62,6 +72,7 @@
             new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
                     new TouchpadFingerState[0]);
     private TouchpadVisualizationView mTouchpadVisualizationView;
+    private final TouchpadHardwareProperties mTouchpadHardwareProperties;
 
     public TouchpadDebugView(Context context, int touchpadId,
             TouchpadHardwareProperties touchpadHardwareProperties) {
@@ -69,10 +80,10 @@
         mTouchpadId = touchpadId;
         mWindowManager =
                 Objects.requireNonNull(getContext().getSystemService(WindowManager.class));
-        init(context, touchpadHardwareProperties, touchpadId);
+        mTouchpadHardwareProperties = touchpadHardwareProperties;
+        init(context, touchpadId);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 
-        // TODO(b/360137366): Use the hardware properties to initialise layout parameters.
         mWindowLayoutParams = new WindowManager.LayoutParams();
         mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
         mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -92,8 +103,8 @@
         mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
     }
 
-    private void init(Context context, TouchpadHardwareProperties touchpadHardwareProperties,
-            int touchpadId) {
+    private void init(Context context, int touchpadId) {
+        updateScreenDimensions();
         setOrientation(VERTICAL);
         setLayoutParams(new LayoutParams(
                 LayoutParams.WRAP_CONTENT,
@@ -102,35 +113,34 @@
 
         TextView nameView = new TextView(context);
         nameView.setBackgroundColor(Color.RED);
-        nameView.setTextSize(20);
+        nameView.setTextSize(TEXT_SIZE_SP);
         nameView.setText(Objects.requireNonNull(Objects.requireNonNull(
                         mContext.getSystemService(InputManager.class))
                 .getInputDevice(touchpadId)).getName());
         nameView.setGravity(Gravity.CENTER);
         nameView.setTextColor(Color.WHITE);
-        nameView.setLayoutParams(new LayoutParams(1000, 200));
+        nameView.setLayoutParams(
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
 
         mTouchpadVisualizationView = new TouchpadVisualizationView(context,
-                touchpadHardwareProperties);
+                mTouchpadHardwareProperties);
         mTouchpadVisualizationView.setBackgroundColor(Color.WHITE);
-        //TODO(b/365568238): set the view size according to the touchpad size from the
-        // TouchpadHardwareProperties
-        mTouchpadVisualizationView.setLayoutParams(new LayoutParams(778, 500));
 
         //TODO(b/365562952): Add a display for recognized gesture info here
         TextView gestureInfoView = new TextView(context);
         gestureInfoView.setBackgroundColor(Color.GRAY);
-        gestureInfoView.setTextSize(20);
+        gestureInfoView.setTextSize(TEXT_SIZE_SP);
         gestureInfoView.setText("Touchpad Debug View 3");
         gestureInfoView.setGravity(Gravity.CENTER);
         gestureInfoView.setTextColor(Color.BLACK);
-        gestureInfoView.setLayoutParams(new LayoutParams(1000, 200));
+        gestureInfoView.setLayoutParams(
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
 
         addView(nameView);
         addView(mTouchpadVisualizationView);
         addView(gestureInfoView);
 
-        updateScreenDimensions();
+        updateViewsDimensions();
     }
 
     @Override
@@ -191,6 +201,7 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         updateScreenDimensions();
+        updateViewsDimensions();
 
         // Adjust view position to stay within screen bounds after rotation
         mWindowLayoutParams.x =
@@ -204,6 +215,41 @@
         return deltaX * deltaX + deltaY * deltaY >= mTouchSlop * mTouchSlop;
     }
 
+    private void updateViewsDimensions() {
+        float resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X
+                : mTouchpadHardwareProperties.getResX();
+        float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y
+                : mTouchpadHardwareProperties.getResY();
+
+        float touchpadHeightMm = Math.abs(
+                mTouchpadHardwareProperties.getBottom() - mTouchpadHardwareProperties.getTop())
+                / resY;
+        float touchpadWidthMm = Math.abs(
+                mTouchpadHardwareProperties.getLeft() - mTouchpadHardwareProperties.getRight())
+                / resX;
+
+        float maxViewWidthPx = mScreenWidth * MAX_SCREEN_WIDTH_PROPORTION;
+        float maxViewHeightPx = mScreenHeight * MAX_SCREEN_HEIGHT_PROPORTION;
+
+        float minScaleFactorPx = TypedValue.applyDimension(COMPLEX_UNIT_DIP, MIN_SCALE_FACTOR,
+                getResources().getDisplayMetrics());
+
+        float scaleFactorBasedOnWidth =
+                touchpadWidthMm * minScaleFactorPx > maxViewWidthPx ? maxViewWidthPx
+                        / touchpadWidthMm : minScaleFactorPx;
+        float scaleFactorBasedOnHeight =
+                touchpadHeightMm * minScaleFactorPx > maxViewHeightPx ? maxViewHeightPx
+                        / touchpadHeightMm : minScaleFactorPx;
+        float scaleFactorUsed = Math.min(scaleFactorBasedOnHeight, scaleFactorBasedOnWidth);
+
+        mTouchpadVisualizationView.setLayoutParams(
+                new LayoutParams((int) (touchpadWidthMm * scaleFactorUsed),
+                        (int) (touchpadHeightMm * scaleFactorUsed)));
+
+        mTouchpadVisualizationView.updateScaleFactor(scaleFactorUsed);
+        mTouchpadVisualizationView.invalidate();
+    }
+
     private void updateScreenDimensions() {
         Rect windowBounds =
                 mWindowManager.getCurrentWindowMetrics().getBounds();
diff --git a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
index 9ba7d0a..2ed6f44 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
@@ -30,8 +30,11 @@
 public class TouchpadVisualizationView extends View {
     private static final String TAG = "TouchpadVizMain";
     private static final boolean DEBUG = true;
+    private static final float DEFAULT_RES_X = 47f;
+    private static final float DEFAULT_RES_Y = 45f;
 
     private final TouchpadHardwareProperties mTouchpadHardwareProperties;
+    private float mScaleFactor;
 
     TouchpadHardwareState mLatestHardwareState = new TouchpadHardwareState(0, 0, 0, 0,
             new TouchpadFingerState[]{});
@@ -42,6 +45,7 @@
             TouchpadHardwareProperties touchpadHardwareProperties) {
         super(context);
         mTouchpadHardwareProperties = touchpadHardwareProperties;
+        mScaleFactor = 1;
         mOvalPaint = new Paint();
         mOvalPaint.setAntiAlias(true);
         mOvalPaint.setARGB(255, 0, 0, 0);
@@ -73,14 +77,16 @@
                     mTouchpadHardwareProperties.getBottom(), 0, getHeight(),
                     touchpadFingerState.getPositionY());
 
-            float newAngle = -translateRange(mTouchpadHardwareProperties.getOrientationMinimum(),
-                    mTouchpadHardwareProperties.getOrientationMaximum(), 0, 360,
-                    touchpadFingerState.getOrientation());
+            float newAngle = translateRange(0, mTouchpadHardwareProperties.getOrientationMaximum(),
+                    0, 90, touchpadFingerState.getOrientation());
 
-            float newTouchMajor =
-                    touchpadFingerState.getTouchMajor() / mTouchpadHardwareProperties.getResX();
-            float newTouchMinor =
-                    touchpadFingerState.getTouchMinor() / mTouchpadHardwareProperties.getResY();
+            float resX = mTouchpadHardwareProperties.getResX() == 0f ? DEFAULT_RES_X
+                    : mTouchpadHardwareProperties.getResX();
+            float resY = mTouchpadHardwareProperties.getResY() == 0f ? DEFAULT_RES_Y
+                    : mTouchpadHardwareProperties.getResY();
+
+            float newTouchMajor = touchpadFingerState.getTouchMajor() * mScaleFactor / resY;
+            float newTouchMinor = touchpadFingerState.getTouchMinor() * mScaleFactor / resX;
 
             drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle, mOvalPaint);
         }
@@ -101,6 +107,15 @@
         invalidate();
     }
 
+    /**
+     * Update the scale factor of the drawings in the view.
+     *
+     * @param scaleFactor the new scale factor
+     */
+    public void updateScaleFactor(float scaleFactor) {
+        mScaleFactor = scaleFactor;
+    }
+
     private float translateRange(float rangeBeforeMin, float rangeBeforeMax,
             float rangeAfterMin, float rangeAfterMax, float value) {
         return rangeAfterMin + (value - rangeBeforeMin) / (rangeBeforeMax - rangeBeforeMin) * (
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7d44ba1..3780fbd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.locksettings;
 
-import static android.security.Flags.reportPrimaryAuthAttempts;
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
 import static android.Manifest.permission.CONFIGURE_FACTORY_RESET_PROTECTION;
 import static android.Manifest.permission.MANAGE_BIOMETRIC;
@@ -32,6 +31,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.UserHandle.USER_ALL;
 import static android.os.UserHandle.USER_SYSTEM;
+import static android.security.Flags.reportPrimaryAuthAttempts;
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
@@ -1836,6 +1836,13 @@
     }
 
     /**
+     * Set a new LSKF for the given user/profile. Only succeeds if the synthetic password for the
+     * user is protected by the given {@param savedCredential}.
+     * <p>
+     * When {@link android.security.Flags#clearStrongAuthOnAddPrimaryCredential()} is enabled and
+     * setting a new credential where there was none, updates the strong auth state for
+     * {@param userId} to <tt>STRONG_AUTH_NOT_REQUIRED</tt>.
+     *
      * @param savedCredential if the user is a profile with
      * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
      *   savedCredential is empty, LSS will try to re-derive the profile password internally.
@@ -1884,6 +1891,12 @@
 
             onSyntheticPasswordUnlocked(userId, sp);
             setLockCredentialWithSpLocked(credential, sp, userId);
+            if (android.security.Flags.clearStrongAuthOnAddPrimaryCredential()
+                    && savedCredential.isNone() && !credential.isNone()) {
+                // Clear the strong auth value, since the LSKF has just been entered and set,
+                // but only when the previous credential was None.
+                mStrongAuth.reportUnlock(userId);
+            }
             sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
             return true;
         }
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index cc58f38..3a429b0 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -1701,7 +1701,7 @@
                     .setGatekeeperHAT(response.getPayload()).build();
             if (response.getShouldReEnroll()) {
                 try {
-                    response = gatekeeper.enroll(userId, spHandle, spHandle,
+                    response = gatekeeper.enroll(userId, spHandle, gatekeeperPassword,
                             gatekeeperPassword);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to invoke gatekeeper.enroll", e);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e2ec006..ba7d4d2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -51,6 +51,7 @@
 import static android.app.NotificationChannel.PROMOTIONS_ID;
 import static android.app.NotificationChannel.RECS_ID;
 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
+import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
 import static android.app.NotificationManager.ACTION_CONSOLIDATED_NOTIFICATION_POLICY_CHANGED;
@@ -109,6 +110,7 @@
 import static android.service.notification.Adjustment.TYPE_PROMOTION;
 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
 import static android.service.notification.Flags.callstyleCallbackApi;
+import static android.service.notification.Flags.notificationClassification;
 import static android.service.notification.Flags.notificationForceGrouping;
 import static android.service.notification.Flags.redactSensitiveNotificationsBigTextStyle;
 import static android.service.notification.Flags.redactSensitiveNotificationsFromUntrustedListeners;
@@ -4405,6 +4407,15 @@
             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
                 throw new IllegalArgumentException("Cannot delete default channel");
             }
+            if (notificationClassification()) {
+                // Check for all reserved channels, but do not throw because it's a common
+                // preexisting pattern for apps to (try to) delete all channels that don't match
+                //  their current desired channel structure
+                if (SYSTEM_RESERVED_IDS.contains(channelId)) {
+                    Log.v(TAG, "Package " + pkg + " cannot delete a reserved channel");
+                    return;
+                }
+            }
             enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
             enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId);
             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 821722b..a4fdb75 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,6 +22,7 @@
 import static android.app.NotificationChannel.PROMOTIONS_ID;
 import static android.app.NotificationChannel.RECS_ID;
 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID;
+import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
@@ -440,6 +441,12 @@
                 channel.setImportanceLockedByCriticalDeviceFunction(
                         r.defaultAppLockedImportance || r.fixedImportance);
 
+                if (notificationClassification()) {
+                    if (SYSTEM_RESERVED_IDS.contains(id) && channel.isDeleted() ) {
+                        channel.setDeleted(false);
+                    }
+                }
+
                 if (isShortcutOk(channel) && isDeletionOk(channel)) {
                     r.channels.put(id, channel);
                 }
@@ -1023,6 +1030,11 @@
             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
                 throw new IllegalArgumentException("Reserved id");
             }
+            // Only the user can update bundle channel settings
+            if (notificationClassification() && !fromSystemOrSystemUi
+                    && SYSTEM_RESERVED_IDS.contains(channel.getId())) {
+                return false;
+            }
             NotificationChannel existing = r.channels.get(channel.getId());
             if (existing != null && fromTargetApp) {
                 // Actually modifying an existing channel - keep most of the existing settings
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index 9ef2e12..f6d9dc2 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -648,6 +648,21 @@
                                     Slog.w(TAG, "Failed to send connected event", ex);
                                 }
                             }
+
+                            @Override
+                            public void onDisconnected(
+                                    @NonNull IOnDeviceSandboxedInferenceService service) {
+                                ensureRemoteIntelligenceServiceInitialized();
+                                mRemoteOnDeviceIntelligenceService.run(
+                                        IOnDeviceIntelligenceService::notifyInferenceServiceDisconnected);
+                            }
+
+                            @Override
+                            public void onBinderDied() {
+                                ensureRemoteIntelligenceServiceInitialized();
+                                mRemoteOnDeviceIntelligenceService.run(
+                                        IOnDeviceIntelligenceService::notifyInferenceServiceDisconnected);
+                            }
                         });
             }
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 023f765..ee15bec 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -92,6 +92,7 @@
 import android.multiuser.Flags;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IInterface;
@@ -214,7 +215,7 @@
 
     @VisibleForTesting
     static class LauncherAppsImpl extends ILauncherApps.Stub {
-        private static final boolean DEBUG = false;
+        private static final boolean DEBUG = Build.IS_DEBUGGABLE;
         private static final String TAG = "LauncherAppsService";
         private static final String NAMESPACE_MULTIUSER = "multiuser";
         private static final String FLAG_NON_SYSTEM_ACCESS_TO_HIDDEN_PROFILES =
@@ -495,8 +496,28 @@
 
         private boolean canAccessProfile(int callingUid, int callingUserId, int callingPid,
                 int targetUserId, String message) {
-            if (targetUserId == callingUserId) return true;
+            if (DEBUG) {
+                final AndroidPackage callingPackage =
+                        mPackageManagerInternal.getPackage(callingUid);
+                final String callingPackageName = callingPackage == null
+                        ? null : callingPackage.getPackageName();
+                Slog.v(TAG, "canAccessProfile called by " + callingPackageName
+                        + " for user " + callingUserId
+                        + " requesting to access user "
+                        + targetUserId + " when invoking " + message);
+            }
+            if (targetUserId == callingUserId) {
+                if (DEBUG) {
+                    Slog.v(TAG, message + " passed canAccessProfile for targetuser"
+                        + targetUserId + " because it is the same as the calling user");
+                }
+                return true;
+            }
             if (injectHasInteractAcrossUsersFullPermission(callingPid, callingUid)) {
+              if (DEBUG) {
+                    Slog.v(TAG, message + " passed because calling process"
+                        + "has permission to interact across users");
+                }
                 return true;
             }
 
@@ -514,11 +535,25 @@
 
             if (isHiddenProfile(UserHandle.of(targetUserId))
                     && !canAccessHiddenProfile(callingUid, callingPid)) {
+                Slog.w(TAG, message + " for hidden profile user " + targetUserId
+                        + " from " + callingUserId + " not allowed");
+
                 return false;
             }
 
-            return mUserManagerInternal.isProfileAccessible(callingUserId, targetUserId,
-                    message, true);
+            final boolean ret = mUserManagerInternal.isProfileAccessible(
+                    callingUserId, targetUserId, message, true);
+            if (DEBUG) {
+                final AndroidPackage callingPackage =
+                        mPackageManagerInternal.getPackage(callingUid);
+                final String callingPackageName = callingPackage == null
+                        ? null : callingPackage.getPackageName();
+                Slog.v(TAG, "canAccessProfile returned " + ret + " for " + callingPackageName
+                        + " for user " + callingUserId
+                        + " requesting to access user "
+                        + targetUserId + " when invoking " + message);
+            }
+            return ret;
         }
 
         private boolean isHiddenProfile(UserHandle targetUser) {
@@ -1341,6 +1376,10 @@
         @Override
         public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
                 UserHandle targetUser) {
+            if (DEBUG) {
+                Slog.v(TAG, "pinShortcuts: " + callingPackage + " is pinning shortcuts from "
+                        + packageName + " for user " + targetUser);
+            }
             if (!mShortcutServiceInternal
                     .areShortcutsSupportedOnHomeScreen(targetUser.getIdentifier())) {
                 // Requires strict ACCESS_SHORTCUTS permission for user-profiles with items
@@ -1351,6 +1390,11 @@
             }
             ensureShortcutPermission(callingPackage);
             if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) {
+                if (DEBUG) {
+                    Slog.v(TAG, "pinShortcuts: " + callingPackage
+                            + " is pinning shortcuts from " + packageName
+                            + " for user " + targetUser + " but cannot access profile");
+                }
                 return;
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index be6fa14..1316df1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -856,8 +856,9 @@
                     params.appPackageName, SYSTEM_UID);
             if (ps != null
                     && PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))
-                    && PackageArchiver.getResponsibleInstallerPackage(ps)
-                            .equals(requestedInstallerPackageName)) {
+                    && TextUtils.equals(
+                        PackageArchiver.getResponsibleInstallerPackage(ps),
+                        requestedInstallerPackageName)) {
                 params.installFlags |= PackageManager.INSTALL_UNARCHIVE;
             }
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 045d4db..d65e30b 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -42,6 +42,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Launcher information used by {@link ShortcutService}.
@@ -128,9 +129,15 @@
      */
     public void pinShortcuts(@UserIdInt int packageUserId,
             @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) {
+        if (ShortcutService.DEBUG) {
+            Slog.v(TAG, "ShortcutLauncher#pinShortcuts: pin shortcuts from " + packageName
+                    + " with userId=" + packageUserId + " shortcutIds="
+                    + ids.stream().collect(Collectors.joining(", ", "[", "]")));
+        }
         final ShortcutPackage packageShortcuts =
                 mShortcutUser.getPackageShortcutsIfExists(packageName);
         if (packageShortcuts == null) {
+            Slog.w(TAG, "ShortcutLauncher#pinShortcuts packageShortcuts is null");
             return; // No need to instantiate.
         }
 
@@ -155,6 +162,10 @@
                 final String id = ids.get(i);
                 final ShortcutInfo si = packageShortcuts.findShortcutById(id);
                 if (si == null) {
+                    if (ShortcutService.DEBUG) {
+                        Slog.w(TAG, "ShortcutLauncher#pinShortcuts: cannot pin "
+                                + id + " because it does not exist");
+                    }
                     continue;
                 }
                 if (si.isDynamic() || si.isLongLived()
@@ -174,6 +185,13 @@
                         }
                     }
                 }
+                if (ShortcutService.DEBUG) {
+                    Slog.v(TAG, "ShortcutLauncher#pinShortcuts: "
+                            + " newSet: " + newSet.stream().collect(
+                                    Collectors.joining(", ", "[", "]"))
+                            + " floatingSet: " + floatingSet.stream().collect(
+                                    Collectors.joining(", ", "[", "]")));
+                }
                 mPinnedShortcuts.put(up, newSet);
             }
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 60056eb..c9ad498 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -729,6 +729,11 @@
             }
             pinnedShortcuts.addAll(pinned);
         });
+        if (ShortcutService.DEBUG) {
+            Slog.v(TAG, "ShortcutPackage#refreshPinnedFlags: "
+                    + " pinnedShortcuts: " + pinnedShortcuts.stream().collect(
+                            Collectors.joining(", ", "[", "]")));
+        }
         // Secondly, update the pinned state if necessary.
         final List<ShortcutInfo> pinned = findAll(pinnedShortcuts);
         if (pinned != null) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a3ff195..ea495c9 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -169,7 +169,7 @@
 public class ShortcutService extends IShortcutService.Stub {
     static final String TAG = "ShortcutService";
 
-    static final boolean DEBUG = false; // STOPSHIP if true
+    static final boolean DEBUG = Build.IS_DEBUGGABLE; // STOPSHIP if true
     static final boolean DEBUG_LOAD = false; // STOPSHIP if true
     static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
     static final boolean DEBUG_REBOOT = Build.IS_DEBUGGABLE;
@@ -3206,6 +3206,11 @@
         public void pinShortcuts(int launcherUserId,
                 @NonNull String callingPackage, @NonNull String packageName,
                 @NonNull List<String> shortcutIds, int userId) {
+            if (DEBUG) {
+                Slog.v(TAG, "pinShortcuts: " + callingPackage + ", with userId=" + launcherUserId
+                        + ", is trying to pin shortcuts from " + packageName
+                        + " with userId=" + userId);
+            }
             // Calling permission must be checked by LauncherAppsImpl.
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Objects.requireNonNull(shortcutIds, "shortcutIds");
@@ -3230,6 +3235,11 @@
                                     && !si.isDeclaredInManifest(),
                             ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO,
                             callingPackage, launcherUserId, false);
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG, "specified package " + packageName + ", with userId=" + userId
+                        + ", doesn't exist.");
+                    }
                 }
                 // Get list of shortcuts that will get unpinned.
                 ArraySet<String> oldPinnedIds = launcher.getPinnedShortcutIds(packageName, userId);
@@ -5448,6 +5458,17 @@
      */
     private List<ShortcutInfo> prepareChangedShortcuts(ArraySet<String> changedIds,
             ArraySet<String> newIds, List<ShortcutInfo> deletedList, final ShortcutPackage ps) {
+        if (DEBUG) {
+            Slog.v(TAG, "prepareChangedShortcuts: "
+                + " changedIds=" + (changedIds == null
+                        ? "n/a" : changedIds.stream().collect(Collectors.joining(", ", "[", "]")))
+                + " newIds=" + (newIds == null
+                        ? "n/a" : newIds.stream().collect(Collectors.joining(", ", "[", "]")))
+                + " deletedList=" + (deletedList == null
+                        ? "n/a" : deletedList.stream().map(ShortcutInfo::getId).collect(
+                                Collectors.joining(", ", "[", "]")))
+                + " ps=" + (ps == null ? "n/a" : ps.getPackageName()));
+        }
         if (ps == null) {
             // This can happen when package restore is not finished yet.
             return null;
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index 4ce01d2..935a238 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -30,10 +30,7 @@
       ]
     },
     {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {"include-filter": "com.android.server.power"}
-      ]
+      "name": "FrameworksServicesTests_android_server_power"
     },
     {
       "name": "PowerServiceTests",
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 6847a5c..dc6b164 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -1628,9 +1628,9 @@
         long mInactivityThresholdMillis = INACTIVITY_THRESHOLD_MILLIS;
 
         void updateThresholds() {
-            synchronized (mSamples) {
-                List<TemperatureThreshold> thresholds =
+            List<TemperatureThreshold> thresholds =
                         mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
+            synchronized (mSamples) {
                 if (Flags.allowThermalHeadroomThresholds()) {
                     Arrays.fill(mHeadroomThresholds, Float.NaN);
                 }
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index f6c3d8e..1346a29 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -160,6 +160,8 @@
     private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint";
     private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager";
 
+    private Boolean mFMQUsesIntegratedEventFlag = false;
+
     @VisibleForTesting final IHintManager.Stub mService = new BinderService();
 
     public HintManagerService(Context context) {
@@ -1032,7 +1034,7 @@
         @Override
         public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
                 @NonNull int[] tids, long durationNanos, @SessionTag int tag,
-                @Nullable SessionConfig config) {
+                SessionConfig config) {
             if (!isHalSupported()) {
                 throw new UnsupportedOperationException("PowerHAL is not supported!");
             }
@@ -1070,7 +1072,7 @@
                         default -> tag = SessionTag.APP;
                     }
                 }
-
+                config.id = -1;
                 Long halSessionPtr = null;
                 if (mConfigCreationSupport.get()) {
                     try {
@@ -1109,7 +1111,7 @@
                     }
                 }
 
-                final long sessionId = config != null ? config.id : halSessionPtr;
+                final long sessionId = config.id != -1 ? config.id : halSessionPtr;
                 logPerformanceHintSessionAtom(
                         callingUid, sessionId, durationNanos, tids, tag);
 
@@ -1144,14 +1146,23 @@
         }
 
         @Override
-        public ChannelConfig getSessionChannel(IBinder token) {
-            if (mPowerHalVersion < 5 || !adpfUseFmqChannel()) {
+        public @Nullable ChannelConfig getSessionChannel(IBinder token) {
+            if (mPowerHalVersion < 5 || !adpfUseFmqChannel()
+                    || mFMQUsesIntegratedEventFlag) {
                 return null;
             }
             java.util.Objects.requireNonNull(token);
             final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
             final int callingUid = Binder.getCallingUid();
             ChannelItem item = getOrCreateMappedChannelItem(callingTgid, callingUid, token);
+            // FMQ V1 requires a separate event flag to be passed, and the default no-op
+            // implmenentation in PowerHAL does not return such a shared flag. This helps
+            // avoid using the FMQ on a default impl that does not support it.
+            if (item.getConfig().eventFlagDescriptor == null) {
+                mFMQUsesIntegratedEventFlag = true;
+                closeSessionChannel();
+                return null;
+            }
             return item.getConfig();
         };
 
@@ -1270,8 +1281,14 @@
         @VisibleForTesting
         boolean updateHintAllowedByProcState(boolean allowed) {
             synchronized (this) {
-                if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) resume();
-                if (!allowed && mUpdateAllowedByProcState) pause();
+                if (allowed && !mUpdateAllowedByProcState && !mShouldForcePause) {
+                    Slogf.e(TAG, "ADPF IS GETTING RESUMED? UID: " + mUid + " TAG: " + mTag);
+                    resume();
+                }
+                if (!allowed && mUpdateAllowedByProcState) {
+                    Slogf.e(TAG, "ADPF IS GETTING PAUSED? UID: " + mUid + " TAG: " + mTag);
+                    pause();
+                }
                 mUpdateAllowedByProcState = allowed;
                 return mUpdateAllowedByProcState;
             }
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 06a2565..8121701 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -51,6 +51,7 @@
 import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_HARDWARE;
 import static android.hardware.SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE;
 import static android.os.UserHandle.USER_NULL;
+import static android.os.UserHandle.getCallingUserId;
 import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
 
 import static com.android.internal.util.FrameworkStatsLog.PRIVACY_SENSOR_TOGGLE_INTERACTION;
@@ -187,6 +188,7 @@
     private final TelephonyManager mTelephonyManager;
     private final PackageManagerInternal mPackageManagerInternal;
     private final NotificationManager mNotificationManager;
+    private final UserManager mUserManager;
 
     private CameraPrivacyLightController mCameraPrivacyLightController;
 
@@ -214,6 +216,7 @@
         mTelephonyManager = context.getSystemService(TelephonyManager.class);
         mPackageManagerInternal = getLocalService(PackageManagerInternal.class);
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
+        mUserManager = context.getSystemService(UserManager.class);
         mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl();
         for (String entry : SystemConfig.getInstance().getCameraPrivacyAllowlist()) {
             mCameraPrivacyAllowlist.add(entry);
@@ -379,14 +382,23 @@
         public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
                 Bundle prevRestrictions) {
             // Reset sensor privacy when restriction is added
+            // Note: isValidCallingUser needs to be called before resetting sensor privacy
+            // because DISALLOW_CAMERA_TOGGLE and DISALLOW_MICROPHONE_TOGGLE are applied on
+            // visible background users in Automotive's Multi Display configuration but we don't
+            // allow sensor privacy to be set on a visible background user.
             if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)
                     && newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) {
-                setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA, false);
+                if (isValidCallingUser(userId)) {
+                    setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, CAMERA,
+                            false);
+                }
             }
             if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)
                     && newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) {
-                setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE,
-                        false);
+                if (isValidCallingUser(userId)) {
+                    setToggleSensorPrivacyUnchecked(TOGGLE_TYPE_SOFTWARE, userId, OTHER, MICROPHONE,
+                            false);
+                }
             }
         }
 
@@ -779,6 +791,10 @@
         @Override
         public void setSensorPrivacy(boolean enable) {
             enforceManageSensorPrivacyPermission();
+
+            // Enforce valid calling user on devices that enable visible background users.
+            enforceValidCallingUser(getCallingUserId());
+
             mSensorPrivacyStateController.setAllSensorState(enable);
         }
 
@@ -795,11 +811,15 @@
                         + " enable=" + enable
                         + ")");
             }
+
             enforceManageSensorPrivacyPermission();
             if (userId == UserHandle.USER_CURRENT) {
                 userId = mCurrentUser;
             }
 
+            // Enforce valid calling user on devices that enable visible background users.
+            enforceValidCallingUser(userId);
+
             if (!canChangeToggleSensorPrivacy(userId, sensor)) {
                 return;
             }
@@ -831,6 +851,9 @@
                 userId = mCurrentUser;
             }
 
+            // Enforce valid calling user on devices that enable visible background users.
+            enforceValidCallingUser(userId);
+
             if (!canChangeToggleSensorPrivacy(userId, sensor)) {
                 return;
             }
@@ -1151,6 +1174,42 @@
             });
         }
 
+        // This method enforces valid calling user on devices that enable visible background users.
+        // Only system user or current user or the user that belongs to the same profile group
+        // as the current user is permitted to toggle sensor privacy.
+        // Visible background users are not permitted to toggle sensor privacy.
+        private void enforceValidCallingUser(@UserIdInt int userId) {
+            if (!isValidCallingUser(userId)) {
+                throw new SecurityException("User " + userId
+                        + " is not permitted to toggle sensor privacy");
+            }
+        }
+
+        private boolean isValidCallingUser(@UserIdInt int userId) {
+            // Check whether visible background users are enabled.
+            // Visible background users are non current but can have UI access.
+            // The main use case for visible background users is the passenger in Automotive's
+            // Multi-Display configuration.
+            if (!UserManager.isVisibleBackgroundUsersEnabled()) {
+                return true;
+            }
+
+            if (userId == UserHandle.USER_SYSTEM || userId == mCurrentUser) {
+                return true;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                if (mUserManager.isSameProfileGroup(userId, mCurrentUser)) {
+                    return true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+
+            return false;
+        }
+
         /**
          * Enforces the caller contains the necessary permission to change the state of sensor
          * privacy.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f52a74f..8c23eaa 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2641,7 +2641,7 @@
             return true;
         }
         // Only do transfer after transaction has done when starting window exist.
-        if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) {
+        if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommitCount > 0) {
             mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT;
             return true;
         }
@@ -2804,9 +2804,11 @@
 
     @Override
     void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
+        // Only add once per transition.
+        final boolean added = wcAwaitingCommit.contains(this);
         super.waitForSyncTransactionCommit(wcAwaitingCommit);
-        if (mStartingData != null) {
-            mStartingData.mWaitForSyncTransactionCommit = true;
+        if (!added && mStartingData != null) {
+            mStartingData.mWaitForSyncTransactionCommitCount++;
         }
     }
 
@@ -2817,7 +2819,7 @@
             return;
         }
         final StartingData lastData = mStartingData;
-        lastData.mWaitForSyncTransactionCommit = false;
+        lastData.mWaitForSyncTransactionCommitCount--;
         if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_REMOVE_DIRECTLY) {
             removeStartingWindowAnimation(lastData.mPrepareRemoveAnimation);
         } else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
@@ -2847,7 +2849,7 @@
         final boolean animate;
         final boolean hasImeSurface;
         if (mStartingData != null) {
-            if (mStartingData.mWaitForSyncTransactionCommit
+            if (mStartingData.mWaitForSyncTransactionCommitCount > 0
                     || mSyncState != SYNC_STATE_NONE) {
                 mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
                 mStartingData.mPrepareRemoveAnimation = prepareAnimation;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 49ca698..3d5b273 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6207,6 +6207,8 @@
         @Override
         public void onProcessAdded(WindowProcessController proc) {
             synchronized (mGlobalLockWithoutBoost) {
+                mPackageConfigPersister.updateConfigIfNeeded(
+                        proc, proc.mUserId, proc.mInfo.packageName);
                 mProcessNames.put(proc.mName, proc.mUid, proc);
             }
         }
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 0646fb7..dd86a14 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -2002,6 +2002,7 @@
         final Transition prepareOpen = migrateBackTransition && !tc.isCollecting()
                 ? tc.createTransition(TRANSIT_PREPARE_BACK_NAVIGATION) : null;
 
+        DisplayContent commonDisplay = null;
         for (int i = affects.size() - 1; i >= 0; --i) {
             final ActivityRecord activity = affects.get(i);
             if (!migrateBackTransition && !activity.isVisibleRequested()) {
@@ -2024,13 +2025,15 @@
             activity.mTaskSupervisor.mStoppingActivities.remove(activity);
 
             if (!migrateBackTransition) {
-                activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
-                        true /* notifyClients */);
+                commonDisplay = activity.getDisplayContent();
             } else if (activity.shouldBeVisible()) {
                 activity.ensureActivityConfiguration(true /* ignoreVisibility */);
                 activity.makeVisibleIfNeeded(null /* starting */, true /* notifyToClient */);
             }
         }
+        if (commonDisplay != null) {
+            commonDisplay.ensureActivitiesVisible(null /* starting */, true /* notifyClients */);
+        }
         if (prepareOpen != null) {
             if (prepareOpen.hasChanges()) {
                 tc.requestStartTransition(prepareOpen,
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index dda39a6..e3232e0 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -16,20 +16,28 @@
 
 package com.android.server.wm;
 
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.CameraCompatTaskInfo;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.view.DisplayInfo;
+import android.view.Surface;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
@@ -172,11 +180,35 @@
     }
 
     private static int getCameraCompatMode(@NonNull ActivityRecord topActivity) {
-        return switch (topActivity.getRequestedConfigurationOrientation()) {
-            case ORIENTATION_PORTRAIT -> CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT;
-            case ORIENTATION_LANDSCAPE -> CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE;
-            default -> CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
-        };
+        final int appOrientation = topActivity.getRequestedConfigurationOrientation();
+        // It is very important to check the original (actual) display rotation, and not the
+        // sandboxed rotation that camera compat treatment sets.
+        final DisplayInfo displayInfo = topActivity.mWmService.mDisplayManagerInternal
+                .getDisplayInfo(topActivity.getDisplayId());
+        // This treatment targets only devices with portrait natural orientation, which most tablets
+        // have.
+        // TODO(b/365725400): handle landscape natural orientation.
+        if (displayInfo.getNaturalHeight() > displayInfo.getNaturalWidth()) {
+            if (appOrientation == ORIENTATION_PORTRAIT) {
+                if (isDisplayRotationPortrait(displayInfo.rotation)) {
+                    return CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
+                } else {
+                    return CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+                }
+            } else if (appOrientation == ORIENTATION_LANDSCAPE) {
+                if (isDisplayRotationPortrait(displayInfo.rotation)) {
+                    return CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
+                } else {
+                    return CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
+                }
+            }
+        }
+
+        return CAMERA_COMPAT_FREEFORM_NONE;
+    }
+
+    private static boolean isDisplayRotationPortrait(@Surface.Rotation int displayRotation) {
+        return displayRotation == ROTATION_0 || displayRotation == ROTATION_180;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
index c3db7dd..cc6904f 100644
--- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
+++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java
@@ -37,8 +37,7 @@
 import android.os.SystemProperties;
 import android.util.Size;
 import android.view.Gravity;
-
-import com.android.server.wm.utils.DesktopModeFlagsUtil;
+import android.window.flags.DesktopModeFlags;
 
 import java.util.function.Consumer;
 
@@ -104,7 +103,7 @@
         final TaskDisplayArea displayArea = task.getDisplayArea();
         final Rect screenBounds = displayArea.getBounds();
         final Size idealSize = calculateIdealSize(screenBounds, DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
-        if (!DesktopModeFlagsUtil.DYNAMIC_INITIAL_BOUNDS.isEnabled(activity.mWmService.mContext)) {
+        if (!DesktopModeFlags.DYNAMIC_INITIAL_BOUNDS.isEnabled(activity.mWmService.mContext)) {
             return centerInScreen(idealSize, screenBounds);
         }
         if (activity.mAppCompatController.getAppCompatAspectRatioOverrides()
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index e0c0c2c..61fbb96 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -19,10 +19,10 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.SystemProperties;
+import android.window.flags.DesktopModeFlags;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wm.utils.DesktopModeFlagsUtil;
 
 /**
  * Constants for desktop mode feature
@@ -36,7 +36,7 @@
 
     /** Whether desktop mode is enabled. */
     static boolean isDesktopModeEnabled(@NonNull Context context) {
-        return DesktopModeFlagsUtil.DESKTOP_WINDOWING_MODE.isEnabled(context);
+        return DesktopModeFlags.DESKTOP_WINDOWING_MODE.isEnabled(context);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index faf6dc6..bc18895 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -109,7 +109,9 @@
 
     // Sets the requested layer to reparent the dim to without applying it immediately
     void setRequestedGeometryParent(WindowContainer<?> geometryParent) {
-        mRequestedProperties.mGeometryParent = geometryParent;
+        if (geometryParent != null) {
+            mRequestedProperties.mGeometryParent = geometryParent;
+        }
     }
 
     // Sets a requested change without applying it immediately
@@ -139,9 +141,14 @@
             dim.remove(t);
             return;
         }
+        if (!dim.mDimSurface.isValid()) {
+            Log.e(TAG, "Dimming surface " + dim.mDimSurface + " has already been released!"
+                    + " Can not apply changes.");
+            return;
+        }
 
         dim.ensureVisible(t);
-        reparent(dim.mDimSurface,
+        reparent(dim,
                 startProperties.mGeometryParent != mRequestedProperties.mGeometryParent
                         ? mRequestedProperties.mGeometryParent.getSurfaceControl() : null,
                 mRequestedProperties.mDimmingContainer != startProperties.mDimmingContainer
@@ -159,7 +166,7 @@
                         "%s skipping animation and directly setting alpha=%f, blur=%d",
                         dim, startProperties.mAlpha,
                         mRequestedProperties.mBlurRadius);
-                setCurrentAlphaBlur(dim.mDimSurface, t);
+                setCurrentAlphaBlur(dim, t);
                 dim.mSkipAnimation = false;
             } else {
                 startAnimation(t, dim, startProperties, mRequestedProperties);
@@ -186,7 +193,7 @@
                     synchronized (dim.mHostContainer.mWmService.mGlobalLock) {
                         SurfaceControl.Transaction finishTransaction =
                                 dim.mHostContainer.getSyncTransaction();
-                        setCurrentAlphaBlur(dim.mDimSurface, finishTransaction);
+                        setCurrentAlphaBlur(dim, finishTransaction);
                         if (targetAlpha == 0f && !dim.isDimming()) {
                             dim.remove(finishTransaction);
                         }
@@ -229,10 +236,11 @@
     /**
      * Change the geometry and relative parent of this dim layer
      */
-    static void reparent(@NonNull SurfaceControl dimLayer,
+    void reparent(@NonNull Dimmer.DimState dim,
                   @Nullable SurfaceControl newGeometryParent,
                   @Nullable SurfaceControl newRelativeParent,
                   @NonNull SurfaceControl.Transaction t) {
+        final SurfaceControl dimLayer = dim.mDimSurface;
         try {
             if (newGeometryParent != null) {
                 t.reparent(dimLayer, newGeometryParent);
@@ -245,7 +253,8 @@
         }
     }
 
-    void setCurrentAlphaBlur(@NonNull SurfaceControl sc, @NonNull SurfaceControl.Transaction t) {
+    void setCurrentAlphaBlur(@NonNull Dimmer.DimState dim, @NonNull SurfaceControl.Transaction t) {
+        final SurfaceControl sc = dim.mDimSurface;
         try {
             t.setAlpha(sc, mCurrentProperties.mAlpha);
             t.setBackgroundBlurRadius(sc, mCurrentProperties.mBlurRadius);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 0daddc0..481ecd3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -380,7 +380,6 @@
         if (android.view.inputmethod.Flags.refactorInsetsController()) {
             notifyInsetsChanged();
             mDisplayContent.updateSystemGestureExclusion();
-            mDisplayContent.updateKeepClearAreas();
             mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
         }
     }
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 24fb207..22c7e8c 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -69,7 +69,7 @@
      * Note this isn't equal to transition playing, the period should be
      * Sync finishNow -> Start transaction apply.
      */
-    boolean mWaitForSyncTransactionCommit;
+    int mWaitForSyncTransactionCommitCount;
 
     /**
      * For Shell transition.
@@ -112,7 +112,7 @@
     public String toString() {
         return getClass().getSimpleName() + "{"
                 + Integer.toHexString(System.identityHashCode(this))
-                + " waitForSyncTransactionCommit=" + mWaitForSyncTransactionCommit
+                + " mWaitForSyncTransactionCommitCount=" + mWaitForSyncTransactionCommitCount
                 + " removeAfterTransaction= " + mRemoveAfterTransaction
                 + "}";
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3bb273c..3490b3e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3806,6 +3806,9 @@
             sb.append(" aI=");
             sb.append(affinityIntent.getComponent().flattenToShortString());
         }
+        sb.append(" isResizeable=").append(isResizeable());
+        sb.append(" minWidth=").append(mMinWidth);
+        sb.append(" minHeight=").append(mMinHeight);
         sb.append('}');
         return stringName = sb.toString();
     }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1eeb3ec..9d46529 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2875,6 +2875,15 @@
     }
 
     /**
+     * Go through the hierarchy to allow windows to request a dim if needed
+     */
+    void adjustDims() {
+        for (int i = 0; i < mChildren.size(); i++) {
+            mChildren.get(i).adjustDims();
+        }
+    }
+
+    /**
      * Trigger a call to prepareSurfaces from the animation thread, such that pending transactions
      * will be applied.
      */
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 87ce866..976be4a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -357,8 +357,6 @@
         }
         mUseFifoUiScheduling = com.android.window.flags.Flags.fifoPriorityForMajorUiProcesses()
                 && (isSysUiPackage || mAtm.isCallerRecents(uid));
-
-        mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName);
     }
 
     public void setPid(int pid) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 021be57..b527630 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4409,6 +4409,17 @@
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             committed |= mChildren.get(i).commitFinishDrawing(t);
         }
+
+        // When a new activity is showing, update dim in this transaction
+        if (Flags.updateDimsWhenWindowShown()) {
+            final Dimmer dimmer = getDimController();
+            final WindowContainer<?> dimParent = getDimParent();
+            if (dimmer != null && dimParent != null) {
+                dimParent.adjustDims();
+                dimmer.updateDims(t);
+            }
+        }
+
         // In case commitFinishDrawingLocked starts a window level animation, make sure the surface
         // operation (reparent to leash) is synced with the visibility by transition.
         if (getAnimationLeash() != null) {
@@ -5304,6 +5315,12 @@
         super.prepareSurfaces();
     }
 
+    @Override
+    void adjustDims() {
+        applyDims();
+        super.adjustDims();
+    }
+
     void updateSurfacePositionIfNeeded() {
         if (mWindowFrames.mRelFrame.top == mWindowFrames.mLastRelFrame.top
                 && mWindowFrames.mRelFrame.left == mWindowFrames.mLastRelFrame.left) {
diff --git a/services/core/java/com/android/server/wm/WindowTracingDataSource.java b/services/core/java/com/android/server/wm/WindowTracingDataSource.java
index dc048ef..b92e525 100644
--- a/services/core/java/com/android/server/wm/WindowTracingDataSource.java
+++ b/services/core/java/com/android/server/wm/WindowTracingDataSource.java
@@ -38,8 +38,6 @@
 
 public final class WindowTracingDataSource extends DataSource<WindowTracingDataSource.Instance,
         WindowTracingDataSource.TlsState, Void> {
-    public static final String DATA_SOURCE_NAME = "android.windowmanager";
-
     public static class TlsState {
         public final Config mConfig;
         public final AtomicBoolean mIsStarting = new AtomicBoolean(true);
@@ -78,8 +76,8 @@
     @NonNull
     private final WeakReference<WindowTracingPerfetto> mWindowTracing;
 
-    public WindowTracingDataSource(WindowTracingPerfetto windowTracing) {
-        super(DATA_SOURCE_NAME);
+    public WindowTracingDataSource(WindowTracingPerfetto windowTracing, String dataSourceName) {
+        super(dataSourceName);
         mWindowTracing = new WeakReference<>(windowTracing);
 
         Producer.init(InitArguments.DEFAULTS);
diff --git a/services/core/java/com/android/server/wm/WindowTracingPerfetto.java b/services/core/java/com/android/server/wm/WindowTracingPerfetto.java
index 22d6c86..6e8094a 100644
--- a/services/core/java/com/android/server/wm/WindowTracingPerfetto.java
+++ b/services/core/java/com/android/server/wm/WindowTracingPerfetto.java
@@ -32,19 +32,21 @@
 
 class WindowTracingPerfetto extends WindowTracing {
     private static final String TAG = "WindowTracing";
+    private static final String PRODUCTION_DATA_SOURCE_NAME = "android.windowmanager";
 
     private final AtomicInteger mCountSessionsOnFrame = new AtomicInteger();
     private final AtomicInteger mCountSessionsOnTransaction = new AtomicInteger();
-    private final WindowTracingDataSource mDataSource = new WindowTracingDataSource(this);
+    private final WindowTracingDataSource mDataSource;
 
     WindowTracingPerfetto(WindowManagerService service, Choreographer choreographer) {
-        this(service, choreographer, service.mGlobalLock);
+        this(service, choreographer, service.mGlobalLock, PRODUCTION_DATA_SOURCE_NAME);
     }
 
     @VisibleForTesting
     WindowTracingPerfetto(WindowManagerService service, Choreographer choreographer,
-            WindowManagerGlobalLock globalLock) {
+            WindowManagerGlobalLock globalLock, String dataSourceName) {
         super(service, choreographer, globalLock);
+        mDataSource = new WindowTracingDataSource(this, dataSourceName);
     }
 
     @Override
diff --git a/services/core/jni/com_android_server_hint_HintManagerService.cpp b/services/core/jni/com_android_server_hint_HintManagerService.cpp
index 2307ace..febfb9f 100644
--- a/services/core/jni/com_android_server_hint_HintManagerService.cpp
+++ b/services/core/jni/com_android_server_hint_HintManagerService.cpp
@@ -109,7 +109,7 @@
         return session_ptr;
     } else if (result.isUnsupported()) {
         throwUnsupported(env, result.errorMessage());
-        return -1;
+        return 0;
     }
     throwFailed(env, result.errorMessage());
     return 0;
@@ -190,7 +190,7 @@
     hal::SessionConfig config;
     jlong out = createHintSessionWithConfig(env, tgid, uid, std::move(threadIds), durationNanos,
                                             sessionTag, config);
-    if (out <= 0) {
+    if (out == 0) {
         return out;
     }
     static jclass configClass = env->FindClass("android/hardware/power/SessionConfig");
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 75db316..b46a6ff 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -95,3 +95,10 @@
     test_suites: ["device-tests"],
     include_filters: ["com.android.server.pm.test.OverlayActorVisibilityTest"],
 }
+
+test_module_config_host {
+    name: "PackageManagerServiceHostTests_android_server_pm_Presubmit",
+    base: "PackageManagerServiceHostTests",
+    test_suites: ["device-tests"],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index 24e931c..f5b0015 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -186,3 +186,13 @@
     include_filters: ["com.android.server.pm."],
     include_annotations: ["android.platform.test.annotations.Postsubmit"],
 }
+
+test_module_config {
+    name: "PackageManagerServiceServerTests_Presubmit",
+    base: "PackageManagerServiceServerTests",
+    test_suites: [
+        "automotive-tests",
+        "device-tests",
+    ],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/VpnTests/Android.bp b/services/tests/VpnTests/Android.bp
index ee20f1a..0568892 100644
--- a/services/tests/VpnTests/Android.bp
+++ b/services/tests/VpnTests/Android.bp
@@ -43,3 +43,10 @@
         "android.test.mock.stubs",
     ],
 }
+
+test_module_config {
+    name: "FrameworksVpnTests_android_server_connectivity",
+    base: "FrameworksVpnTests",
+    test_suites: ["device-tests"],
+    exclude_annotations: ["com.android.testutils.SkipPresubmit"],
+}
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
index 3ebf689..b938c3c 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
@@ -16,15 +16,24 @@
 package com.android.server.appfunctions
 
 import android.app.appfunctions.AppFunctionRuntimeMetadata
+import android.app.appfunctions.AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema
+import android.app.appfunctions.AppFunctionStaticMetadataHelper
 import android.app.appsearch.AppSearchManager
 import android.app.appsearch.AppSearchManager.SearchContext
+import android.app.appsearch.GenericDocument
 import android.app.appsearch.PutDocumentsRequest
+import android.app.appsearch.SearchResult
+import android.app.appsearch.SearchSpec
 import android.app.appsearch.SetSchemaRequest
 import android.util.ArrayMap
 import android.util.ArraySet
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.infra.AndroidFuture
+import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults
 import com.google.common.truth.Truth.assertThat
 import com.google.common.util.concurrent.MoreExecutors
+import java.util.concurrent.Executor
+import java.util.concurrent.atomic.AtomicBoolean
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -36,6 +45,7 @@
     private val context = InstrumentationRegistry.getInstrumentation().targetContext
     private val appSearchManager = context.getSystemService(AppSearchManager::class.java)
     private val testExecutor = MoreExecutors.directExecutor()
+    private val packageManager = context.packageManager
 
     @Before
     @After
@@ -72,6 +82,7 @@
             MetadataSyncAdapter(
                 testExecutor,
                 FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
+                packageManager,
             )
         val packageToFunctionIdMap =
             metadataSyncAdapter.getPackageToFunctionIdMap(
@@ -122,6 +133,7 @@
             MetadataSyncAdapter(
                 testExecutor,
                 FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
+                packageManager,
             )
         val packageToFunctionIdMap =
             metadataSyncAdapter.getPackageToFunctionIdMap(
@@ -159,6 +171,70 @@
     }
 
     @Test
+    fun syncMetadata_noDiff() {
+        val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+        val appSearchSession =
+            PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
+        val fakeFunctionId = "syncMetadata_noDiff"
+        val fakeStaticMetadata: GenericDocument =
+            GenericDocument.Builder<GenericDocument.Builder<*>>(
+                    AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE,
+                    AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(
+                        TEST_TARGET_PKG_NAME,
+                        fakeFunctionId,
+                    ),
+                    AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
+                )
+                .setPropertyString(
+                    AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME,
+                    TEST_TARGET_PKG_NAME,
+                )
+                .setPropertyString(
+                    AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
+                    fakeFunctionId,
+                )
+                .build()
+        appSearchSession.overrideStaticMetadataSearchResult = mutableListOf(fakeStaticMetadata)
+        val putCorrespondingSchema =
+            appSearchSession
+                .setSchema(
+                    SetSchemaRequest.Builder()
+                        .addSchemas(
+                            createParentAppFunctionRuntimeSchema(),
+                            AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(
+                                TEST_TARGET_PKG_NAME
+                            ),
+                        )
+                        .setForceOverride(true)
+                        .build()
+                )
+                .get()
+        assertThat(putCorrespondingSchema).isNotNull()
+        val putCorrespondingRuntimeMetadata =
+            appSearchSession
+                .put(
+                    PutDocumentsRequest.Builder()
+                        .addGenericDocuments(
+                            AppFunctionRuntimeMetadata.Builder(
+                                    TEST_TARGET_PKG_NAME,
+                                    fakeFunctionId,
+                                    "",
+                                )
+                                .build()
+                        )
+                        .build()
+                )
+                .get()
+        assertThat(putCorrespondingRuntimeMetadata.isSuccess).isTrue()
+        val metadataSyncAdapter =
+            MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+
+        val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+
+        assertThat(submitSyncRequest.get()).isTrue()
+    }
+
+    @Test
     fun getAddedFunctionsDiffMap_addedFunction() {
         val staticPackageToFunctionMap: ArrayMap<String, ArraySet<String>> = ArrayMap()
         staticPackageToFunctionMap.putAll(
@@ -180,6 +256,39 @@
     }
 
     @Test
+    fun syncMetadata_addedFunction() {
+        val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+        val appSearchSession =
+            PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
+        val fakeFunctionId = "addedFunction1"
+        val fakeStaticMetadata: GenericDocument =
+            GenericDocument.Builder<GenericDocument.Builder<*>>(
+                    AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE,
+                    AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(
+                        TEST_TARGET_PKG_NAME,
+                        fakeFunctionId,
+                    ),
+                    AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
+                )
+                .setPropertyString(
+                    AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME,
+                    TEST_TARGET_PKG_NAME,
+                )
+                .setPropertyString(
+                    AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
+                    fakeFunctionId,
+                )
+                .build()
+        appSearchSession.overrideStaticMetadataSearchResult = mutableListOf(fakeStaticMetadata)
+        val metadataSyncAdapter =
+            MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+
+        val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+
+        assertThat(submitSyncRequest.get()).isTrue()
+    }
+
+    @Test
     fun getAddedFunctionsDiffMap_addedFunctionNewPackage() {
         val staticPackageToFunctionMap: ArrayMap<String, ArraySet<String>> = ArrayMap()
         staticPackageToFunctionMap.putAll(
@@ -215,6 +324,51 @@
     }
 
     @Test
+    fun syncMetadata_removedFunction() {
+        val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+        val appSearchSession =
+            PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
+        val fakeFunctionId = "syncMetadata_removedFunction"
+        val putCorrespondingSchema =
+            appSearchSession
+                .setSchema(
+                    SetSchemaRequest.Builder()
+                        .addSchemas(
+                            createParentAppFunctionRuntimeSchema(),
+                            AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(
+                                TEST_TARGET_PKG_NAME
+                            ),
+                        )
+                        .setForceOverride(true)
+                        .build()
+                )
+                .get()
+        assertThat(putCorrespondingSchema).isNotNull()
+        val putStaleRuntimeMetadata =
+            appSearchSession
+                .put(
+                    PutDocumentsRequest.Builder()
+                        .addGenericDocuments(
+                            AppFunctionRuntimeMetadata.Builder(
+                                    TEST_TARGET_PKG_NAME,
+                                    fakeFunctionId,
+                                    "",
+                                )
+                                .build()
+                        )
+                        .build()
+                )
+                .get()
+        assertThat(putStaleRuntimeMetadata.isSuccess).isTrue()
+        val metadataSyncAdapter =
+            MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+
+        val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+
+        assertThat(submitSyncRequest.get()).isTrue()
+    }
+
+    @Test
     fun getRemovedFunctionsDiffMap_noDiff() {
         val staticPackageToFunctionMap: ArrayMap<String, ArraySet<String>> = ArrayMap()
         staticPackageToFunctionMap.putAll(
@@ -271,4 +425,49 @@
         const val TEST_DB: String = "test_db"
         const val TEST_TARGET_PKG_NAME = "com.android.frameworks.appfunctionstests"
     }
+
+    class PartialFakeFutureAppSearchSession(
+        appSearchManager: AppSearchManager,
+        executor: Executor,
+        appSearchContext: SearchContext,
+    ) : FutureAppSearchSessionImpl(appSearchManager, executor, appSearchContext) {
+        var overrideStaticMetadataSearchResult: MutableList<GenericDocument> = mutableListOf()
+        private val overrideUsed = AtomicBoolean(false)
+
+        // Overriding this method to fake searching for static metadata.
+        // Static metadata is the source of truth for the metadata sync behaviour since the sync is
+        // updating the runtime metadata to match the existing static metadata.
+        override fun search(
+            queryExpression: String,
+            searchSpec: SearchSpec,
+        ): AndroidFuture<FutureSearchResults> {
+            if (
+                searchSpec.filterSchemas.contains(
+                    AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE
+                )
+            ) {
+                val futureSearchResults =
+                    object : FutureSearchResults {
+                        override fun getNextPage(): AndroidFuture<MutableList<SearchResult>> {
+                            if (overrideUsed.get()) {
+                                overrideStaticMetadataSearchResult.clear()
+                                return AndroidFuture.completedFuture(mutableListOf())
+                            }
+                            overrideUsed.set(true)
+                            return AndroidFuture.completedFuture(
+                                overrideStaticMetadataSearchResult
+                                    .map {
+                                        SearchResult.Builder(TEST_TARGET_PKG_NAME, TEST_DB)
+                                            .setGenericDocument(it)
+                                            .build()
+                                    }
+                                    .toMutableList()
+                            )
+                        }
+                    }
+                return AndroidFuture.completedFuture(futureSearchResults)
+            }
+            return super.search(queryExpression, searchSpec)
+        }
+    }
 }
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index fe73025..36ea241 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -22,6 +22,7 @@
     static_libs: [
         "androidx.test.ext.junit",
         "androidx.test.rules",
+        "compatibility-device-util-axt",
         "flag-junit",
         "frameworks-base-testutils",
         "junit",
@@ -48,6 +49,10 @@
         "automotive-tests",
     ],
 
+    data: [
+        ":DisplayManagerTestApp",
+    ],
+
     certificate: "platform",
 
     dxflags: ["--multi-dex"],
diff --git a/services/tests/displayservicetests/AndroidManifest.xml b/services/tests/displayservicetests/AndroidManifest.xml
index 74260cd..37a34ee 100644
--- a/services/tests/displayservicetests/AndroidManifest.xml
+++ b/services/tests/displayservicetests/AndroidManifest.xml
@@ -39,6 +39,10 @@
                  android:testOnly="true">
         <uses-library android:name="android.test.mock" android:required="true" />
         <uses-library android:name="android.test.runner" />
+        <activity android:name="com.android.server.display.SimpleActivity"
+                  android:exported="true" />
+        <activity android:name="com.android.server.display.SimpleActivity2"
+                  android:exported="true" />
     </application>
 
     <instrumentation
diff --git a/services/tests/displayservicetests/AndroidTest.xml b/services/tests/displayservicetests/AndroidTest.xml
index 2985f98..f3697bb 100644
--- a/services/tests/displayservicetests/AndroidTest.xml
+++ b/services/tests/displayservicetests/AndroidTest.xml
@@ -23,6 +23,13 @@
         <option name="test-file-name" value="DisplayServiceTests.apk" />
     </target_preparer>
 
+    <!-- Load additional APKs onto device -->
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="DisplayManagerTestApp.apk" />
+    </target_preparer>
+
     <option name="test-tag" value="DisplayServiceTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="com.android.frameworks.displayservicetests" />
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java
new file mode 100644
index 0000000..90f6257
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayEventDeliveryTest.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.util.DisplayMetrics.DENSITY_HIGH;
+import static android.util.DisplayMetrics.DENSITY_MEDIUM;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.platform.test.annotations.AppModeSdkSandbox;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests that applications can receive display events correctly.
+ */
+@RunWith(Parameterized.class)
+@AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
+public class DisplayEventDeliveryTest {
+    private static final String TAG = "DisplayEventDeliveryTest";
+
+    private static final String NAME = TAG;
+    private static final int WIDTH = 720;
+    private static final int HEIGHT = 480;
+
+    private static final int MESSAGE_LAUNCHED = 1;
+    private static final int MESSAGE_CALLBACK = 2;
+
+    private static final int DISPLAY_ADDED = 1;
+    private static final int DISPLAY_CHANGED = 2;
+    private static final int DISPLAY_REMOVED = 3;
+
+    private static final long DISPLAY_EVENT_TIMEOUT_MSEC = 100;
+    private static final long TEST_FAILURE_TIMEOUT_MSEC = 10000;
+
+    private static final String TEST_PACKAGE =
+            "com.android.servicestests.apps.displaymanagertestapp";
+    private static final String TEST_ACTIVITY = TEST_PACKAGE + ".DisplayEventActivity";
+    private static final String TEST_DISPLAYS = "DISPLAYS";
+    private static final String TEST_MESSENGER = "MESSENGER";
+
+    private final Object mLock = new Object();
+
+    private Instrumentation mInstrumentation;
+    private Context mContext;
+    private DisplayManager mDisplayManager;
+    private ActivityManager mActivityManager;
+    private ActivityManager.OnUidImportanceListener mUidImportanceListener;
+    private CountDownLatch mLatchActivityLaunch;
+    private CountDownLatch mLatchActivityCached;
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+    private Messenger mMessenger;
+    private int mPid;
+    private int mUid;
+
+    /**
+     * Array of DisplayBundle. The test handler uses it to check if certain display events have
+     * been sent to DisplayEventActivity.
+     * Key: displayId of each new VirtualDisplay created by this test
+     * Value: DisplayBundle, storing the VirtualDisplay and its expected display events
+     *
+     * NOTE: The lock is required when adding and removing virtual displays. Otherwise it's not
+     * necessary to lock mDisplayBundles when accessing it from the test function.
+     */
+    @GuardedBy("mLock")
+    private SparseArray<DisplayBundle> mDisplayBundles;
+
+    /**
+     * Helper class to store VirtualDisplay and its corresponding display events expected to be
+     * sent to DisplayEventActivity.
+     */
+    private static final class DisplayBundle {
+        private VirtualDisplay mVirtualDisplay;
+        private final int mDisplayId;
+
+        // Display events we expect to receive before timeout
+        private final LinkedBlockingQueue<Integer> mExpectations;
+
+        DisplayBundle(VirtualDisplay display) {
+            mVirtualDisplay = display;
+            mDisplayId = display.getDisplay().getDisplayId();
+            mExpectations = new LinkedBlockingQueue<>();
+        }
+
+        public void releaseDisplay() {
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.release();
+            }
+            mVirtualDisplay = null;
+        }
+
+        /**
+         * Add the received display event from the test activity to the queue
+         *
+         * @param event The corresponding display event
+         */
+        public void addDisplayEvent(int event) {
+            Log.d(TAG, "Received " + mDisplayId + " " + event);
+            mExpectations.offer(event);
+        }
+
+
+        /**
+         * Assert that there isn't any unexpected display event from the test activity
+         */
+        public void assertNoDisplayEvents() {
+            try {
+                assertNull(mExpectations.poll(DISPLAY_EVENT_TIMEOUT_MSEC, TimeUnit.MILLISECONDS));
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Wait for the expected display event from the test activity
+         *
+         * @param expect The expected display event
+         */
+        public void waitDisplayEvent(int expect) {
+            while (true) {
+                try {
+                    final Integer event;
+                    event = mExpectations.poll(TEST_FAILURE_TIMEOUT_MSEC, TimeUnit.MILLISECONDS);
+                    assertNotNull(event);
+                    if (expect == event) {
+                        Log.d(TAG, "Found    " + mDisplayId + " " + event);
+                        return;
+                    }
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * How many virtual displays to create during the test
+     */
+    @Parameter(0)
+    public int mDisplayCount;
+
+    /**
+     * True if running the test activity in cached mode
+     * False if running it in non-cached mode
+     */
+    @Parameter(1)
+    public boolean mCached;
+
+    @Parameters(name = "#{index}: {0} {1}")
+    public static Iterable<? extends Object> data() {
+        return Arrays.asList(new Object[][]{
+                {1, false}, {2, false}, {3, false}, {10, false},
+                {1, true}, {2, true}, {3, true}, {10, true}
+        });
+    }
+
+    private class TestHandler extends Handler {
+        TestHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(@NonNull Message msg) {
+            switch (msg.what) {
+                case MESSAGE_LAUNCHED:
+                    mPid = msg.arg1;
+                    mUid = msg.arg2;
+                    Log.d(TAG, "Launched " + mPid + " " + mUid);
+                    mLatchActivityLaunch.countDown();
+                    break;
+                case MESSAGE_CALLBACK:
+                    Log.d(TAG, "Callback " + msg.arg1 + " " + msg.arg2);
+                    synchronized (mLock) {
+                        // arg1: displayId
+                        DisplayBundle bundle = mDisplayBundles.get(msg.arg1);
+                        if (bundle != null) {
+                            // arg2: display event
+                            bundle.addDisplayEvent(msg.arg2);
+                        }
+                    }
+                    break;
+                default:
+                    fail("Unexpected value: " + msg.what);
+                    break;
+            }
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mContext = mInstrumentation.getContext();
+        mDisplayManager = mContext.getSystemService(DisplayManager.class);
+        mLatchActivityLaunch = new CountDownLatch(1);
+        mLatchActivityCached = new CountDownLatch(1);
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        mUidImportanceListener = (uid, importance) -> {
+            if (uid == mUid && importance == IMPORTANCE_CACHED) {
+                Log.d(TAG, "Listener " + uid + " becomes " + importance);
+                mLatchActivityCached.countDown();
+            }
+        };
+        SystemUtil.runWithShellPermissionIdentity(() ->
+                mActivityManager.addOnUidImportanceListener(mUidImportanceListener,
+                        IMPORTANCE_CACHED));
+        // The lock is not functionally necessary but eliminates lint error messages.
+        synchronized (mLock) {
+            mDisplayBundles = new SparseArray<>();
+        }
+        mHandlerThread = new HandlerThread("handler");
+        mHandlerThread.start();
+        mHandler = new TestHandler(mHandlerThread.getLooper());
+        mMessenger = new Messenger(mHandler);
+        mPid = 0;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mActivityManager.removeOnUidImportanceListener(mUidImportanceListener);
+        mHandlerThread.quitSafely();
+        synchronized (mLock) {
+            for (int i = 0; i < mDisplayBundles.size(); i++) {
+                DisplayBundle bundle = mDisplayBundles.valueAt(i);
+                // Clean up unreleased virtual display
+                bundle.releaseDisplay();
+            }
+            mDisplayBundles.clear();
+        }
+        SystemUtil.runShellCommand(mInstrumentation, "am force-stop " + TEST_PACKAGE);
+    }
+
+    /**
+     * Return a display bundle at the stated index.  The bundle is retrieved under lock.
+     */
+    private DisplayBundle displayBundleAt(int i) {
+        synchronized (mLock) {
+            return mDisplayBundles.valueAt(i);
+        }
+    }
+
+    /**
+     * Create virtual displays, change their configurations and release them
+     * mDisplays: the amount of virtual displays to be created
+     * mCached: true to run the test activity in cached mode; false in non-cached mode
+     */
+    @Test
+    public void testDisplayEvents() {
+        Log.d(TAG, "Start test testDisplayEvents " + mDisplayCount + " " + mCached);
+        // Launch DisplayEventActivity and start listening to display events
+        launchTestActivity();
+
+        if (mCached) {
+            // The test activity in cached mode won't receive the pending display events
+            makeTestActivityCached();
+        }
+
+        // Create new virtual displays
+        for (int i = 0; i < mDisplayCount; i++) {
+            // Lock is needed here to ensure the handler can query the displays
+            synchronized (mLock) {
+                VirtualDisplay display = createVirtualDisplay(NAME + i);
+                DisplayBundle bundle = new DisplayBundle(display);
+                mDisplayBundles.put(bundle.mDisplayId, bundle);
+            }
+        }
+
+        for (int i = 0; i < mDisplayCount; i++) {
+            if (mCached) {
+                // DISPLAY_ADDED should be deferred for cached process
+                displayBundleAt(i).assertNoDisplayEvents();
+            } else {
+                // DISPLAY_ADDED should arrive immediately for non-cached process
+                displayBundleAt(i).waitDisplayEvent(DISPLAY_ADDED);
+            }
+        }
+
+        // Change the virtual displays
+        for (int i = 0; i < mDisplayCount; i++) {
+            DisplayBundle bundle = displayBundleAt(i);
+            bundle.mVirtualDisplay.resize(WIDTH, HEIGHT, DENSITY_HIGH);
+        }
+
+        for (int i = 0; i < mDisplayCount; i++) {
+            if (mCached) {
+                // DISPLAY_CHANGED should be deferred for cached process
+                displayBundleAt(i).assertNoDisplayEvents();
+            } else {
+                // DISPLAY_CHANGED should arrive immediately for non-cached process
+                displayBundleAt(i).waitDisplayEvent(DISPLAY_CHANGED);
+            }
+        }
+
+        if (mCached) {
+            // The test activity becomes non-cached and should receive the pending display events
+            bringTestActivityTop();
+
+            for (int i = 0; i < mDisplayCount; i++) {
+                // The pending DISPLAY_ADDED & DISPLAY_CHANGED should arrive now
+                displayBundleAt(i).waitDisplayEvent(DISPLAY_ADDED);
+                displayBundleAt(i).waitDisplayEvent(DISPLAY_CHANGED);
+            }
+        }
+
+        // Release the virtual displays
+        for (int i = 0; i < mDisplayCount; i++) {
+            displayBundleAt(i).releaseDisplay();
+        }
+
+        // DISPLAY_REMOVED should arrive now
+        for (int i = 0; i < mDisplayCount; i++) {
+            displayBundleAt(i).waitDisplayEvent(DISPLAY_REMOVED);
+        }
+    }
+
+    /**
+     * Launch the test activity that would listen to display events
+     */
+    private void launchTestActivity() {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(TEST_PACKAGE, TEST_ACTIVITY);
+        intent.putExtra(TEST_MESSENGER, mMessenger);
+        intent.putExtra(TEST_DISPLAYS, mDisplayCount);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        SystemUtil.runWithShellPermissionIdentity(
+                () -> {
+                    mContext.startActivity(intent);
+                },
+                android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
+        waitLatch(mLatchActivityLaunch);
+    }
+
+    /**
+     * Bring the test activity back to top
+     */
+    private void bringTestActivityTop() {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(TEST_PACKAGE, TEST_ACTIVITY);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+        SystemUtil.runWithShellPermissionIdentity(
+                () -> {
+                    mContext.startActivity(intent);
+                },
+                android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
+    }
+
+    /**
+     * Bring the test activity into cached mode by launching another 2 apps
+     */
+    private void makeTestActivityCached() {
+        // Launch another activity to bring the test activity into background
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClass(mContext, SimpleActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+
+        // Launch another activity to bring the test activity into cached mode
+        Intent intent2 = new Intent(Intent.ACTION_MAIN);
+        intent2.setClass(mContext, SimpleActivity2.class);
+        intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        SystemUtil.runWithShellPermissionIdentity(
+                () -> {
+                    mInstrumentation.startActivitySync(intent);
+                    mInstrumentation.startActivitySync(intent2);
+                },
+                android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX);
+        waitLatch(mLatchActivityCached);
+    }
+
+    /**
+     * Create a virtual display
+     *
+     * @param name The name of the new virtual display
+     * @return The new virtual display
+     */
+    private VirtualDisplay createVirtualDisplay(String name) {
+        return mDisplayManager.createVirtualDisplay(name, WIDTH, HEIGHT, DENSITY_MEDIUM,
+                null /* surface: as we don't actually draw anything, null is enough */,
+                VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+                /* flags: a public virtual display that another app can access */);
+    }
+
+    /**
+     * Wait for CountDownLatch with timeout
+     */
+    private void waitLatch(CountDownLatch latch) {
+        try {
+            latch.await(TEST_FAILURE_TIMEOUT_MSEC, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 76c8e686..8b80f85 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -117,6 +117,7 @@
 import android.provider.Settings.SettingNotFoundException;
 import android.test.mock.MockContentResolver;
 import android.util.SparseArray;
+import android.util.Spline;
 import android.view.ContentRecordingSession;
 import android.view.Display;
 import android.view.DisplayAdjustments;
@@ -141,6 +142,7 @@
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 import com.android.server.display.DisplayManagerService.DeviceStateListener;
 import com.android.server.display.DisplayManagerService.SyncRoot;
+import com.android.server.display.config.HdrBrightnessData;
 import com.android.server.display.config.SensorData;
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.layout.Layout;
@@ -3203,6 +3205,45 @@
     }
 
     @Test
+    public void testHighestHdrSdrRatio() {
+        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+        displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        float highestRatio = 9.5f;
+        HdrBrightnessData hdrData = new HdrBrightnessData(Collections.emptyMap(),
+                /* brightnessIncreaseDebounceMillis= */ 0, /* screenBrightnessRampIncrease= */ 0,
+                /* brightnessDecreaseDebounceMillis= */ 0, /* screenBrightnessRampDecrease= */ 0,
+                /* hbmTransitionPoint= */ 0, /* minimumHdrPercentOfScreenForNbm= */ 0,
+                /* minimumHdrPercentOfScreenForHbm= */ 0, /* allowInLowPowerMode= */ false,
+                mock(Spline.class), highestRatio);
+        when(mMockDisplayDeviceConfig.getHdrBrightnessData()).thenReturn(hdrData);
+
+        assertEquals(highestRatio, displayManagerBinderService.getHighestHdrSdrRatio(displayId),
+                /* delta= */ 0);
+    }
+
+    @Test
+    public void testHighestHdrSdrRatio_HdrDataNull() {
+        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f});
+        displayDevice.mDisplayDeviceConfig = mMockDisplayDeviceConfig;
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        when(mMockDisplayDeviceConfig.getHdrBrightnessData()).thenReturn(null);
+
+        assertEquals(1, displayManagerBinderService.getHighestHdrSdrRatio(displayId),
+                /* delta= */ 0);
+    }
+
+    @Test
     public void testOnDisplayChanged_HbmMetadataNull() {
         DisplayPowerController dpc = mock(DisplayPowerController.class);
         DisplayManagerService.Injector injector = new BasicInjector() {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java
new file mode 100644
index 0000000..c4ebbd9
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.app.Activity;
+
+/**
+ * An activity doing nothing
+ */
+public final class SimpleActivity extends Activity { }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java
new file mode 100644
index 0000000..a719a57
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/SimpleActivity2.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.app.Activity;
+
+/**
+ * Another activity doing nothing
+ */
+public final class SimpleActivity2 extends Activity { }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
index c758033..0db7de4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/config/DisplayDeviceConfigTestUtils.kt
@@ -61,7 +61,8 @@
     minimumHdrPercentOfScreenForNbm: Float = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
     minimumHdrPercentOfScreenForHbm: Float = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT,
     allowInLowPowerMode: Boolean = false,
-    sdrToHdrRatioSpline: Spline? = null
+    sdrToHdrRatioSpline: Spline? = null,
+    highestHdrSdrRatio: Float = 1f
 ): HdrBrightnessData {
     return HdrBrightnessData(
         maxBrightnessLimits,
@@ -73,7 +74,8 @@
         minimumHdrPercentOfScreenForNbm,
         minimumHdrPercentOfScreenForHbm,
         allowInLowPowerMode,
-        sdrToHdrRatioSpline
+        sdrToHdrRatioSpline,
+        highestHdrSdrRatio
     )
 }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt b/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
index 917c681..48920d8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/config/HdrBrightnessDataTest.kt
@@ -28,7 +28,7 @@
 class HdrBrightnessDataTest {
 
     @Test
-    fun `test HdrBrightnessData default configuration`() {
+    fun testHdrBrightnessData_defaultConfiguration() {
         val displayConfiguration = createDisplayConfiguration {
             hdrBrightnessConfig(
                 brightnessDecreaseDebounceMillis = "3000",
@@ -64,10 +64,11 @@
         )
         assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
         assertThat(hdrBrightnessData.sdrToHdrRatioSpline).isNull()
+        assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(1)
     }
 
     @Test
-    fun `test HdrBrightnessData fallback configuration`() {
+    fun testHdrBrightnessData_fallbackConfiguration() {
         val displayConfiguration = createDisplayConfiguration {
             hdrBrightnessConfig(
                 minimumHdrPercentOfScreenForNbm = null,
@@ -77,7 +78,7 @@
             )
             highBrightnessMode(
                 minimumHdrPercentOfScreen = "0.2",
-                sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+                sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "7.0"))
             )
         }
 
@@ -91,17 +92,18 @@
         assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.2f)
         assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
 
-        val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 8.0f))
+        val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 7.0f))
         assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
             .isEqualTo(expectedSpline.toString())
+        assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(7)
     }
 
     @Test
-    fun `test HdrBrightnessData fallback configuration no hdrBrightnessConfig`() {
+    fun testHdrBrightnessData_fallbackConfiguration_noHdrBrightnessConfig() {
         val displayConfiguration = createDisplayConfiguration {
             highBrightnessMode(
                 minimumHdrPercentOfScreen = "0.2",
-                sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+                sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "7.0"))
             )
         }
 
@@ -124,13 +126,14 @@
         assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.2f)
         assertThat(hdrBrightnessData.allowInLowPowerMode).isFalse()
 
-        val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 8.0f))
+        val expectedSpline = createSpline(floatArrayOf(2.0f, 5.0f), floatArrayOf(4.0f, 7.0f))
         assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
             .isEqualTo(expectedSpline.toString())
+        assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(7)
     }
 
     @Test
-    fun `test HdrBrightnessData configuration no configuration`() {
+    fun testHdrBrightnessData_emptyConfiguration() {
         val displayConfiguration = createDisplayConfiguration()
 
         val hdrBrightnessData = HdrBrightnessData.loadConfig(displayConfiguration) { 0.6f }
@@ -138,17 +141,17 @@
     }
 
     @Test
-    fun `test HdrBrightnessData real configuration`() {
+    fun testHdrBrightnessData_realConfiguration() {
         val displayConfiguration = createDisplayConfiguration {
             hdrBrightnessConfig(
                 minimumHdrPercentOfScreenForNbm = "0.3",
                 minimumHdrPercentOfScreenForHbm = "0.6",
                 allowInLowPowerMode = "true",
-                sdrHdrRatioMap = listOf(Pair("3.0", "5.0"), Pair("6.0", "8.0"))
+                sdrHdrRatioMap = listOf(Pair("3.0", "5.0"), Pair("6.0", "7.0"))
             )
             highBrightnessMode(
                 minimumHdrPercentOfScreen = "0.2",
-                sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "8.0"))
+                sdrHdrRatioMap = listOf(Pair("2.0", "4.0"), Pair("5.0", "7.5"))
             )
         }
 
@@ -162,8 +165,9 @@
         assertThat(hdrBrightnessData.minimumHdrPercentOfScreenForHbm).isEqualTo(0.6f)
         assertThat(hdrBrightnessData.allowInLowPowerMode).isTrue()
 
-        val expectedSpline = createSpline(floatArrayOf(3.0f, 6.0f), floatArrayOf(5.0f, 8.0f))
+        val expectedSpline = createSpline(floatArrayOf(3.0f, 6.0f), floatArrayOf(5.0f, 7.0f))
         assertThat(hdrBrightnessData.sdrToHdrRatioSpline.toString())
             .isEqualTo(expectedSpline.toString())
+        assertThat(hdrBrightnessData.highestHdrSdrRatio).isEqualTo(7)
     }
 }
\ No newline at end of file
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 1abc557..1128f52 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -39,7 +39,6 @@
 import android.view.WindowManager;
 
 import androidx.annotation.NonNull;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -106,6 +105,12 @@
             mMonitor.onEndDream();
             super.onEndDream();
         }
+
+        @Override
+        public void onWakeUp() {
+            mMonitor.onWakeUp();
+            super.onWakeUp();
+        }
     }
 
     /**
@@ -128,7 +133,6 @@
      * Verifies that callbacks for subclasses are run on the provided executor.
      */
     @Test
-    @FlakyTest(bugId = 293108088)
     public void testCallbacksRunOnExecutor() throws RemoteException {
         final TestDreamOverlayService.Monitor monitor = Mockito.mock(
                 TestDreamOverlayService.Monitor.class);
@@ -153,6 +157,8 @@
         // Callback is run.
         verify(monitor).onStartDream();
 
+        clearInvocations(mExecutor);
+
         // Verify onWakeUp is run on the executor.
         client.wakeUp();
         verify(monitor, never()).onWakeUp();
@@ -161,6 +167,8 @@
         mRunnableCaptor.getValue().run();
         verify(monitor).onWakeUp();
 
+        clearInvocations(mExecutor);
+
         // Verify onEndDream is run on the executor.
         client.endDream();
         verify(monitor, never()).onEndDream();
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 6fc80b8..c81d6be 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -391,3 +391,13 @@
     ],
     include_filters: ["com.android.server.trust"],
 }
+
+test_module_config {
+    name: "FrameworksMockingServicesTests_server_storagemanagerservicetest",
+    base: "FrameworksMockingServicesTests",
+    test_suites: [
+        "automotive-tests",
+        "device-tests",
+    ],
+    include_filters: ["com.android.server.StorageManagerServiceTest"],
+}
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index b2ca991..639ae30 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -48,7 +48,9 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.power.ChannelConfig;
+import android.hardware.power.ChannelMessage;
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
@@ -167,6 +169,8 @@
         mConfig = new ChannelConfig();
         mConfig.readFlagBitmask = 1;
         mConfig.writeFlagBitmask = 2;
+        mConfig.channelDescriptor = new MQDescriptor<ChannelMessage, Byte>();
+        mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>();
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
         when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
index e4ab227..38fc6a9 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
@@ -39,11 +39,11 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.SystemClock;
 import android.platform.test.ravenwood.RavenwoodRule;
@@ -52,10 +52,10 @@
 import android.util.DebugUtils;
 import android.util.KeyValueListParser;
 import android.util.Log;
+import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
 import androidx.test.uiautomator.UiDevice;
 
 import com.android.frameworks.coretests.aidl.ICmdCallback;
@@ -66,7 +66,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
@@ -103,6 +102,7 @@
 
     private static final int GENERAL_TIMEOUT_MS = 4000;
     private static final int GENERAL_INTERVAL_MS = 200;
+    private static final int SCREEN_STATE_CHANGE_TIMEOUT_MS = 10000;
 
     private static final int WORK_DURATION_MS = 2000;
 
@@ -110,6 +110,7 @@
     private static String sOriginalBatteryStatsConsts;
 
     private static Context sContext;
+    private static Display sDisplay;
     private static UiDevice sUiDevice;
     private static int sTestPkgUid;
     private static boolean sCpuFreqTimesAvailable;
@@ -131,6 +132,10 @@
         sTestPkgUid = sContext.getPackageManager().getPackageUid(TEST_PKG, 0);
         executeCmd("cmd deviceidle whitelist +" + TEST_PKG);
         checkCpuTimesAvailability();
+        DisplayManager displayManager = sContext.getSystemService(DisplayManager.class);
+        if (displayManager != null) {
+            sDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        }
     }
 
     @AfterClass
@@ -833,12 +838,12 @@
         executeCmd("input keyevent KEYCODE_WAKEUP");
         executeCmd("wm dismiss-keyguard");
         assertKeyguardUnLocked();
-        assertScreenInteractive(true);
+        assertScreenState(true);
     }
 
     private void screenoff() throws Exception {
         executeCmd("input keyevent KEYCODE_SLEEP");
-        assertScreenInteractive(false);
+        assertScreenState(false);
     }
 
     private void forceStop() throws Exception {
@@ -854,12 +859,15 @@
         );
     }
 
-    private void assertScreenInteractive(boolean interactive) throws Exception {
-        final PowerManager powerManager =
-                (PowerManager) sContext.getSystemService(Context.POWER_SERVICE);
-        assertDelayedCondition("Unexpected screen interactive state", () ->
-                interactive == powerManager.isInteractive() ? null : "expected=" + interactive
-        );
+    private void assertScreenState(boolean expectedOn) throws Exception {
+        if (sDisplay == null) {
+            return;
+        }
+
+        assertDelayedCondition("Unexpected screen-on state",
+                () -> expectedOn == Display.isOnState(sDisplay.getState())
+                        ? null : "expected=" + expectedOn,
+                SCREEN_STATE_CHANGE_TIMEOUT_MS, GENERAL_INTERVAL_MS);
     }
 
     private void assertDelayedCondition(String errMsgPrefix, ExpectedCondition condition)
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 895cd1e..b41b30c 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -30,6 +30,7 @@
         "src/**/*.kt",
 
         "test-apps/SuspendTestApp/src/**/*.java",
+        "test-apps/DisplayManagerTestApp/src/**/*.java",
     ],
 
     kotlincflags: [
@@ -134,6 +135,7 @@
     },
 
     data: [
+        ":DisplayManagerTestApp",
         ":SimpleServiceTestApp1",
         ":SimpleServiceTestApp2",
         ":SimpleServiceTestApp3",
@@ -278,14 +280,22 @@
 test_module_config {
     name: "FrameworksServicesTests_contentprotection",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.contentprotection"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_om",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.om."],
 }
 
@@ -293,7 +303,11 @@
 test_module_config {
     name: "FrameworksServicesTests_contexthub_presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.location.contexthub."],
     // TODO(ron): are these right, does it run anything?
     include_annotations: ["android.platform.test.annotations.Presubmit"],
@@ -302,7 +316,11 @@
 test_module_config {
     name: "FrameworksServicesTests_contexthub_postsubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.location.contexthub."],
     // TODO(ron): are these right, does it run anything?
     include_annotations: ["android.platform.test.annotations.Postsubmit"],
@@ -312,14 +330,22 @@
 test_module_config {
     name: "FrameworksServicesTests_contentcapture",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.contentcapture"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_recoverysystem",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.recoverysystem."],
 }
 
@@ -327,7 +353,11 @@
 test_module_config {
     name: "FrameworksServicesTests_pm_presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_annotations: ["android.platform.test.annotations.Presubmit"],
     include_filters: ["com.android.server.pm."],
 }
@@ -335,7 +365,11 @@
 test_module_config {
     name: "FrameworksServicesTests_pm_postsubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_annotations: ["android.platform.test.annotations.Postsubmit"],
     include_filters: ["com.android.server.pm."],
 }
@@ -344,21 +378,33 @@
 test_module_config {
     name: "FrameworksServicesTests_os",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.os."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_com_android_server_job_Presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.job"],
     exclude_annotations: [
         "androidx.test.filters.LargeTest",
@@ -369,49 +415,77 @@
 test_module_config {
     name: "FrameworksServicesTests_com_android_server_job",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.job"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_com_android_server_tare",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.tare"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_com_android_server_usage",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.usage"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_battery_stats",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.am.BatteryStatsServiceTest"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_accessibility",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.accessibility"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_binary_transparency",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.BinaryTransparencyServiceTest"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_pinner_service",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.PinnerServiceTest"],
     exclude_annotations: ["org.junit.Ignore"],
 }
@@ -419,7 +493,11 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_am_Presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.am."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -427,21 +505,33 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_am",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.am."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_appop",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.appop"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_audio",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.audio"],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -449,14 +539,22 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_compat",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.compat"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_hdmi_Presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.hdmi"],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -464,35 +562,55 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_hdmi",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.hdmi"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_integrity",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.integrity."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_lights",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.lights"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_locales",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.locales."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_location_contexthub_Presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.location.contexthub."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -500,21 +618,33 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_locksettings",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.locksettings."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_logcat",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.logcat"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_net_Presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.net."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -522,28 +652,44 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_om",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.om."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_pdb",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.pdb.PersistentDataBlockServiceTest"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_pm_dex",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.pm.dex"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_policy_Presubmit",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.policy."],
     include_annotations: ["android.platform.test.annotations.Presubmit"],
 }
@@ -551,49 +697,77 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_policy",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.policy."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_power",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.power"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_power_hint",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.power.hint"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_powerstats",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.powerstats"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_rollback",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.rollback"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_uri",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.uri."],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_com_android_server_location_contexthub",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.location.contexthub."],
     include_annotations: ["android.platform.test.annotations.Postsubmit"],
 }
@@ -601,7 +775,11 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_usage",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.usage"],
     exclude_filters: ["com.android.server.usage.StorageStatsServiceTest"],
 }
@@ -609,14 +787,22 @@
 test_module_config {
     name: "FrameworksServicesTests_android_server_soundtrigger_middleware",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.soundtrigger_middleware"],
 }
 
 test_module_config {
     name: "FrameworksServicesTests_android_server_input",
     base: "FrameworksServicesTests",
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "automotive-tests",
+    ],
+
     include_filters: ["com.android.server.input"],
 }
 
@@ -792,3 +978,23 @@
     ],
     include_filters: ["com.android.server.input"],
 }
+
+test_module_config {
+    name: "FrameworksServicesTests_people_data",
+    base: "FrameworksServicesTests",
+    test_suites: [
+        "automotive-tests",
+        "device-tests",
+    ],
+    include_filters: ["com.android.server.people.data"],
+}
+
+test_module_config {
+    name: "FrameworksServicesTests_Presubmit",
+    base: "FrameworksServicesTests",
+    test_suites: [
+        "automotive-tests",
+        "device-tests",
+    ],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index b56af87..5298251 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -35,6 +35,7 @@
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="DisplayManagerTestApp.apk" />
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
         <option name="test-file-name" value="SuspendTestApp.apk" />
         <option name="test-file-name" value="SimpleServiceTestApp1.apk" />
diff --git a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java
index bc3a5ca..2ff0c62 100644
--- a/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/DiscreteAppOpPersistenceTest.java
@@ -86,7 +86,8 @@
         int attributionChainId = AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
 
         mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
-                uidState, accessTime, duration, attributionFlags, attributionChainId);
+                uidState, accessTime, duration, attributionFlags, attributionChainId,
+                DiscreteRegistry.ACCESS_TYPE_FINISH_OP);
 
         // Verify in-memory object is correct
         fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
@@ -117,7 +118,8 @@
         int attributionChainId = 10;
 
         mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
-                uidState, accessTime, duration, attributionFlags, attributionChainId);
+                uidState, accessTime, duration, attributionFlags, attributionChainId,
+                DiscreteRegistry.ACCESS_TYPE_START_OP);
 
         fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
                 duration, uidState, opFlags, attributionFlags, attributionChainId);
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 2ba3969..87c9db2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -92,6 +92,7 @@
 
     MockLockSettingsContext mContext;
     LockSettingsStorageTestable mStorage;
+    LockSettingsStrongAuth mStrongAuth;
 
     Resources mResources;
     FakeGateKeeperService mGateKeeperService;
@@ -135,6 +136,7 @@
         mFingerprintManager = mock(FingerprintManager.class);
         mFaceManager = mock(FaceManager.class);
         mPackageManager = mock(PackageManager.class);
+        mStrongAuth = mock(LockSettingsStrongAuth.class);
 
         LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -162,7 +164,7 @@
         mInjector =
                 new LockSettingsServiceTestable.MockInjector(
                         mContext,
-                        mStorage,
+                        mStorage, mStrongAuth,
                         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 93fc071a..abd39b0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -50,6 +50,7 @@
     public static class MockInjector extends LockSettingsService.Injector {
 
         private LockSettingsStorage mLockSettingsStorage;
+        private final LockSettingsStrongAuth mStrongAuth;
         private IActivityManager mActivityManager;
         private IStorageManager mStorageManager;
         private SyntheticPasswordManager mSpManager;
@@ -62,12 +63,14 @@
         public boolean mIsMainUserPermanentAdmin = false;
 
         public MockInjector(Context context, LockSettingsStorage storage,
+                LockSettingsStrongAuth strongAuth,
                 IActivityManager activityManager, IStorageManager storageManager,
                 SyntheticPasswordManager spManager, FakeGsiService gsiService,
                 RecoverableKeyStoreManager recoverableKeyStoreManager,
                 UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
             super(context);
             mLockSettingsStorage = storage;
+            mStrongAuth = strongAuth;
             mActivityManager = activityManager;
             mStorageManager = storageManager;
             mSpManager = spManager;
@@ -89,7 +92,7 @@
 
         @Override
         public LockSettingsStrongAuth getStrongAuth() {
-            return mock(LockSettingsStrongAuth.class);
+            return mStrongAuth;
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 601a016..2868e55 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -17,6 +17,7 @@
 package com.android.server.locksettings;
 
 import static android.Manifest.permission.CONFIGURE_FACTORY_RESET_PROTECTION;
+import static android.security.Flags.FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL;
 import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS;
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -46,6 +47,10 @@
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 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.platform.test.flag.junit.SetFlagsRule;
 import android.service.gatekeeper.GateKeeperResponse;
 import android.text.TextUtils;
@@ -71,6 +76,8 @@
 @RunWith(AndroidJUnit4.class)
 public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Before
     public void setUp() {
@@ -258,6 +265,34 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+    public void setLockCredential_forPrimaryUser_clearsStrongAuthWhenFlagIsOn()
+            throws Exception {
+        setCredential(PRIMARY_USER_ID, newPassword("password"));
+
+        verify(mStrongAuth).reportUnlock(PRIMARY_USER_ID);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+    public void setLockCredential_forPrimaryUser_leavesStrongAuthWhenFlagIsOff()
+            throws Exception {
+        setCredential(PRIMARY_USER_ID, newPassword("password"));
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
+    @Test
+    public void setLockCredential_forPrimaryUserWithCredential_leavesStrongAuth() throws Exception {
+        setCredential(PRIMARY_USER_ID, newPassword("password"));
+        reset(mStrongAuth);
+
+        setCredential(PRIMARY_USER_ID, newPassword("password2"), newPassword("password"));
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
+    @Test
     public void testSetLockCredential_forProfileWithSeparateChallenge_sendsCredentials()
             throws Exception {
         setCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
@@ -278,6 +313,28 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+    public void setLockCredential_profileWithNewSeparateChallenge_clearsStrongAuthWhenFlagIsOn()
+            throws Exception {
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
+
+        setCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
+
+        verify(mStrongAuth).reportUnlock(MANAGED_PROFILE_USER_ID);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+    public void setLockCredential_profileWithNewSeparateChallenge_leavesStrongAuthWhenFlagIsOff()
+            throws Exception {
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
+
+        setCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
+    @Test
     public void testSetLockCredential_forProfileWithUnifiedChallenge_doesNotSendRandomCredential()
             throws Exception {
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
@@ -305,6 +362,67 @@
                         MANAGED_PROFILE_USER_ID);
     }
 
+
+    @Test
+    public void setLockCredential_primaryWithUnifiedProfileAndCredential_leavesStrongAuthForBoth()
+            throws Exception {
+        final LockscreenCredential oldCredential = newPassword("oldPassword");
+        final LockscreenCredential newCredential = newPassword("newPassword");
+        setCredential(PRIMARY_USER_ID, oldCredential);
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+        reset(mStrongAuth);
+
+        setCredential(PRIMARY_USER_ID, newCredential, oldCredential);
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+    public void setLockCredential_primaryWithUnifiedProfile_clearsStrongAuthForBothWhenFlagIsOn()
+            throws Exception {
+        final LockscreenCredential credential = newPassword("oldPassword");
+        setCredential(PRIMARY_USER_ID, credential);
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+        clearCredential(PRIMARY_USER_ID, credential);
+        reset(mStrongAuth);
+
+        setCredential(PRIMARY_USER_ID, credential);
+
+        verify(mStrongAuth).reportUnlock(PRIMARY_USER_ID);
+        verify(mStrongAuth).reportUnlock(MANAGED_PROFILE_USER_ID);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_CLEAR_STRONG_AUTH_ON_ADD_PRIMARY_CREDENTIAL)
+    public void setLockCredential_primaryWithUnifiedProfile_leavesStrongAuthForBothWhenFlagIsOff()
+            throws Exception {
+        final LockscreenCredential credential = newPassword("oldPassword");
+        setCredential(PRIMARY_USER_ID, credential);
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+        clearCredential(PRIMARY_USER_ID, credential);
+        reset(mStrongAuth);
+
+        setCredential(PRIMARY_USER_ID, credential);
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
+
+    @Test
+    public void setLockCredential_primaryWithUnifiedProfileWithCredential_leavesStrongAuthForBoth()
+            throws Exception {
+        final LockscreenCredential oldCredential = newPassword("oldPassword");
+        final LockscreenCredential newCredential = newPassword("newPassword");
+        setCredential(PRIMARY_USER_ID, oldCredential);
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+        reset(mStrongAuth);
+
+        setCredential(PRIMARY_USER_ID, newCredential, oldCredential);
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
     @Test
     public void
             testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
@@ -343,6 +461,18 @@
     }
 
     @Test
+    public void clearLockCredential_primaryWithUnifiedProfile_leavesStrongAuthForBoth()
+            throws Exception {
+        setCredential(PRIMARY_USER_ID, newPassword("password"));
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+        reset(mStrongAuth);
+
+        clearCredential(PRIMARY_USER_ID, newPassword("password"));
+
+        verify(mStrongAuth, never()).reportUnlock(anyInt());
+    }
+
+    @Test
     public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials()
             throws Exception {
         final LockscreenCredential parentPassword = newPassword("parentPassword");
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/Android.bp b/services/tests/servicestests/test-apps/DisplayManagerTestApp/Android.bp
new file mode 100644
index 0000000..962ae9b
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/Android.bp
@@ -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 {
+    // 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_helper_app {
+    name: "DisplayManagerTestApp",
+
+    sdk_version: "current",
+
+    srcs: ["**/*.java"],
+
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/DisplayManagerTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..c0d9d6f
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?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.servicestests.apps.displaymanagertestapp">
+
+    <application android:label="DisplayEventTestApp">
+        <activity android:name=".DisplayEventActivity"
+                  android:exported="true" />
+    </application>
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/OWNERS b/services/tests/servicestests/test-apps/DisplayManagerTestApp/OWNERS
new file mode 100644
index 0000000..e9557f8
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 345010
+
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/services/tests/servicestests/test-apps/DisplayManagerTestApp/src/com/android/servicestests/apps/displaymanagertestapp/DisplayEventActivity.java b/services/tests/servicestests/test-apps/DisplayManagerTestApp/src/com/android/servicestests/apps/displaymanagertestapp/DisplayEventActivity.java
new file mode 100644
index 0000000..07754b2
--- /dev/null
+++ b/services/tests/servicestests/test-apps/DisplayManagerTestApp/src/com/android/servicestests/apps/displaymanagertestapp/DisplayEventActivity.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.servicestests.apps.displaymanagertestapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A simple activity manipulating displays and listening to corresponding display events
+ */
+public class DisplayEventActivity extends Activity {
+    private static final String TAG = DisplayEventActivity.class.getSimpleName();
+
+    private static final String TEST_DISPLAYS = "DISPLAYS";
+    private static final String TEST_MESSENGER = "MESSENGER";
+
+    private static final int MESSAGE_LAUNCHED = 1;
+    private static final int MESSAGE_CALLBACK = 2;
+
+    private static final int DISPLAY_ADDED = 1;
+    private static final int DISPLAY_CHANGED = 2;
+    private static final int DISPLAY_REMOVED = 3;
+
+    private int mExpectedDisplayCount;
+    private int mSeenDisplayCount;
+    private Messenger mMessenger;
+    private DisplayManager mDisplayManager;
+    private DisplayManager.DisplayListener mDisplayListener;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+        mExpectedDisplayCount = 0;
+        mSeenDisplayCount = intent.getIntExtra(TEST_DISPLAYS, 0);
+        mMessenger = intent.getParcelableExtra(TEST_MESSENGER, Messenger.class);
+        mDisplayManager = getApplicationContext().getSystemService(DisplayManager.class);
+        mDisplayListener = new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+                callback(displayId, DISPLAY_ADDED);
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                callback(displayId, DISPLAY_REMOVED);
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                callback(displayId, DISPLAY_CHANGED);
+            }
+        };
+        Handler handler = new Handler(Looper.getMainLooper());
+        mDisplayManager.registerDisplayListener(mDisplayListener, handler);
+        launched();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mDisplayManager.unregisterDisplayListener(mDisplayListener);
+    }
+
+    private void launched() {
+        try {
+            Message msg = Message.obtain();
+            msg.what = MESSAGE_LAUNCHED;
+            msg.arg1 = Process.myPid();
+            msg.arg2 = Process.myUid();
+            Log.d(TAG, "Launched " + mSeenDisplayCount);
+            mMessenger.send(msg);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    private void callback(int displayId, int event) {
+        try {
+            Message msg = Message.obtain();
+            msg.what = MESSAGE_CALLBACK;
+            msg.arg1 = displayId;
+            msg.arg2 = event;
+            Log.d(TAG, "Msg " + msg.arg1 + " " + msg.arg2);
+            mMessenger.send(msg);
+            if (event == DISPLAY_REMOVED) {
+                mExpectedDisplayCount++;
+                if (mExpectedDisplayCount >= mSeenDisplayCount) {
+                    finish();
+                }
+            }
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 850d2f7..a63a38d 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -92,3 +92,13 @@
     // Required for TestParameterInjector
     javacflags: ["-parameters"],
 }
+
+test_module_config {
+    name: "FrameworksUiServicesTests_notification",
+    base: "FrameworksUiServicesTests",
+    test_suites: [
+        "automotive-tests",
+        "device-tests",
+    ],
+    exclude_annotations: ["androidx.test.filters.LargeTest"],
+}
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 196bc47..96ddf80 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -99,6 +99,7 @@
 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_NOTIFICATION_CLASSIFICATION;
 import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING;
 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -4412,7 +4413,7 @@
                 eq(mTestNotificationChannel.getId()), anyBoolean()))
                 .thenReturn(mTestNotificationChannel);
         when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
-                eq(mTestNotificationChannel.getId()),  anyInt(), anyBoolean())).thenReturn(true);
+                eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true);
         reset(mListeners);
         mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId());
         verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg),
@@ -4421,6 +4422,24 @@
     }
 
     @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testAppsCannotDeleteBundleChannel() throws Exception {
+        when(mCompanionMgr.getAssociations(mPkg, mUserId))
+                .thenReturn(singletonList(mock(AssociationInfo.class)));
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
+                eq(NEWS_ID), anyBoolean()))
+                .thenReturn(mTestNotificationChannel);
+        when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(),
+                eq(NEWS_ID), anyInt(), anyBoolean())).thenReturn(true);
+        reset(mListeners);
+        mBinderService.deleteNotificationChannel(mPkg, NEWS_ID);
+        verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
+                eq(Process.myUserHandle()), any(),
+                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
+    }
+
+    @Test
     public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
         when(mCompanionMgr.getAssociations(mPkg, mUserId))
                 .thenReturn(singletonList(mock(AssociationInfo.class)));
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 559c324..1905ae4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -6222,6 +6222,47 @@
                 .isEqualTo(IMPORTANCE_LOW);
     }
 
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testNotificationBundles_appsCannotUpdate() {
+        // do something that triggers settings creation for an app
+        mHelper.setShowBadge(PKG_O, UID_O, true);
+
+        NotificationChannel fromApp =
+                new NotificationChannel(NEWS_ID, "The best channel", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(PKG_O, UID_O, fromApp, true, false, UID_O, false);
+
+        assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, NEWS_ID, false).getImportance())
+                .isEqualTo(IMPORTANCE_LOW);
+    }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testNotificationBundles_osCanAllowToBypassDnd() {
+        // do something that triggers settings creation for an app
+        mHelper.setShowBadge(PKG_O, UID_O, true);
+
+        NotificationChannel fromApp =
+                new NotificationChannel(NEWS_ID, "The best channel", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(PKG_O, UID_O, fromApp, true, false, UID_O, false);
+    }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testUnDeleteBundleChannelsOnLoadIfNotUserChange() throws Exception {
+        mHelper.setShowBadge(PKG_P, UID_P, true);
+        // the public create/update methods should prevent this, so take advantage of the fact that
+        // the object is in the same process
+        mHelper.getNotificationChannel(PKG_P, UID_P, SOCIAL_MEDIA_ID, true).setDeleted(true);
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
+                UserHandle.USER_ALL, SOCIAL_MEDIA_ID);
+
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
+
+        assertThat(mXmlHelper.getNotificationChannel(PKG_P, UID_P, SOCIAL_MEDIA_ID, true).
+                isDeleted()).isFalse();
+    }
 
     @Test
     public void testRestoredWithoutUid_threadSafety() throws Exception {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index c706d52..c176658 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -932,7 +932,6 @@
         WindowProcessController wpc = createWindowProcessController(
                 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
         mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
-        mAtm.mInternal.onProcessAdded(wpc);
 
         ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal
                 .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
@@ -987,7 +986,6 @@
         WindowProcessController wpc = createWindowProcessController(
                 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
         mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
-        mAtm.mInternal.onProcessAdded(wpc);
 
         ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
                 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME,
@@ -1018,7 +1016,6 @@
         WindowProcessController wpc = createWindowProcessController(
                 DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
         mAtm.mProcessMap.put(Binder.getCallingPid(), wpc);
-        mAtm.mInternal.onProcessAdded(wpc);
 
         ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater =
                 mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME,
@@ -1048,6 +1045,7 @@
         WindowProcessController wpc = new WindowProcessController(
                 mAtm, info, packageName, 0, userId, null, mMockListener);
         mAtm.mInternal.preBindApplication(wpc, info);
+        mAtm.mInternal.onProcessAdded(wpc);
         wpc.setThread(mock(IApplicationThread.class));
         return wpc;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index 5a3ae76..a48813d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -16,11 +16,17 @@
 
 package com.android.server.wm;
 
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -33,10 +39,10 @@
 
 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.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -55,6 +61,8 @@
 import android.hardware.camera2.CameraManager;
 import android.os.Handler;
 import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.Surface;
 
 import androidx.test.filters.SmallTest;
 
@@ -134,6 +142,7 @@
                 new CameraCompatFreeformPolicy(mDisplayContent, cameraStateMonitor,
                         mActivityRefresher);
 
+        setDisplayRotation(Surface.ROTATION_90);
         mCameraCompatFreeformPolicy.start();
         cameraStateMonitor.startListeningToCameraState();
     }
@@ -162,17 +171,49 @@
     }
 
     @Test
-    public void testCameraConnected_activatesCameraCompatMode() throws Exception {
+    public void testCameraConnected_deviceInPortrait_portraitCameraCompatMode() throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+        setDisplayRotation(Surface.ROTATION_0);
         mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
 
-        assertInCameraCompatMode();
+        assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_PORTRAIT);
+        assertActivityRefreshRequested(/* refreshRequested */ false);
+    }
+
+    @Test
+    public void testCameraConnected_deviceInLandscape_portraitCameraCompatMode() throws Exception {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+        setDisplayRotation(Surface.ROTATION_270);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
+        assertActivityRefreshRequested(/* refreshRequested */ false);
+    }
+
+    @Test
+    public void testCameraConnected_deviceInPortrait_landscapeCameraCompatMode() throws Exception {
+        configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
+        setDisplayRotation(Surface.ROTATION_0);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_PORTRAIT);
+        assertActivityRefreshRequested(/* refreshRequested */ false);
+    }
+
+    @Test
+    public void testCameraConnected_deviceInLandscape_landscapeCameraCompatMode() throws Exception {
+        configureActivity(SCREEN_ORIENTATION_LANDSCAPE);
+        setDisplayRotation(Surface.ROTATION_270);
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_LANDSCAPE_DEVICE_IN_LANDSCAPE);
         assertActivityRefreshRequested(/* refreshRequested */ false);
     }
 
     @Test
     public void testCameraReconnected_cameraCompatModeAndRefresh() throws Exception {
         configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+        setDisplayRotation(Surface.ROTATION_270);
 
         mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
         callOnActivityConfigurationChanging(mActivity);
@@ -180,7 +221,7 @@
         mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
         callOnActivityConfigurationChanging(mActivity);
 
-        assertInCameraCompatMode();
+        assertInCameraCompatMode(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
         assertActivityRefreshRequested(/* refreshRequested */ true);
     }
 
@@ -285,16 +326,14 @@
         doReturn(true).when(mActivity).inFreeformWindowingMode();
     }
 
-    private void assertInCameraCompatMode() {
-        assertNotEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
-                mActivity.mAppCompatController.getAppCompatCameraOverrides()
+    private void assertInCameraCompatMode(@CameraCompatTaskInfo.FreeformCameraCompatMode int mode) {
+        assertEquals(mode, mActivity.mAppCompatController.getAppCompatCameraOverrides()
                         .getFreeformCameraCompatMode());
     }
 
     private void assertNotInCameraCompatMode() {
-        assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
-                mActivity.mAppCompatController.getAppCompatCameraOverrides()
-                        .getFreeformCameraCompatMode());
+        assertEquals(CAMERA_COMPAT_FREEFORM_NONE, mActivity.mAppCompatController
+                .getAppCompatCameraOverrides().getFreeformCameraCompatMode());
     }
 
     private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
@@ -328,4 +367,19 @@
         configuration.windowConfiguration.setAppBounds(bounds);
         return configuration;
     }
+
+    private void setDisplayRotation(@Surface.Rotation int displayRotation) {
+        doAnswer(invocation -> {
+            DisplayInfo displayInfo = new DisplayInfo();
+            mDisplayContent.getDisplay().getDisplayInfo(displayInfo);
+            displayInfo.rotation = displayRotation;
+            // Set height so that the natural orientation (rotation is 0) is portrait. This is the
+            // case for most standard phones and tablets.
+            // TODO(b/365725400): handle landscape natural orientation.
+            displayInfo.logicalHeight = displayRotation % 180 == 0 ? 800 : 600;
+            displayInfo.logicalWidth =  displayRotation % 180 == 0 ? 600 : 800;
+            return displayInfo;
+        }).when(mDisplayContent.mWmService.mDisplayManagerInternal)
+                .getDisplayInfo(anyInt());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 45082d2..7ff2e50 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,7 +16,9 @@
 
 package com.android.server.wm;
 
+
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -71,7 +73,6 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.CameraCompatTaskInfo;
 import android.app.TaskInfo;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
@@ -2025,10 +2026,10 @@
     public void getTaskInfoPropagatesCameraCompatMode() {
         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         final ActivityRecord activity = task.getTopMostActivity();
-        activity.mAppCompatController.getAppCompatCameraOverrides()
-                .setFreeformCameraCompatMode(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT);
+        activity.mAppCompatController.getAppCompatCameraOverrides().setFreeformCameraCompatMode(
+                CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE);
 
-        assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT,
+        assertEquals(CAMERA_COMPAT_FREEFORM_PORTRAIT_DEVICE_IN_LANDSCAPE,
                 task.getTaskInfo().appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
index c45b99d..4104999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingPerfettoTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 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.
@@ -28,6 +28,7 @@
 import static java.io.File.createTempFile;
 import static java.nio.file.Files.createTempDirectory;
 
+import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.Presubmit;
 import android.tools.ScenarioBuilder;
 import android.tools.traces.io.ResultWriter;
@@ -35,107 +36,187 @@
 import android.view.Choreographer;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.google.protobuf.InvalidProtocolBufferException;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mockito;
 
+import perfetto.protos.PerfettoConfig.TracingServiceState;
 import perfetto.protos.PerfettoConfig.WindowManagerConfig.LogFrequency;
 
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Optional;
+
 /**
  * Test class for {@link WindowTracingPerfetto}.
  */
 @SmallTest
 @Presubmit
 public class WindowTracingPerfettoTest {
-    private WindowManagerService mWmMock;
-    private Choreographer mChoreographer;
-    private WindowTracing mWindowTracing;
+    private static final String TEST_DATA_SOURCE_NAME = "android.windowmanager.test";
+
+    private static WindowManagerService sWmMock;
+    private static Choreographer sChoreographer;
+    private static WindowTracing sWindowTracing;
+
     private PerfettoTraceMonitor mTraceMonitor;
-    private ResultWriter mWriter;
+
+    @BeforeClass
+    public static void setUpOnce() throws Exception {
+        sWmMock = Mockito.mock(WindowManagerService.class);
+        Mockito.doNothing().when(sWmMock).dumpDebugLocked(Mockito.any(), Mockito.anyInt());
+        sChoreographer = Mockito.mock(Choreographer.class);
+        sWindowTracing = new WindowTracingPerfetto(sWmMock, sChoreographer,
+                new WindowManagerGlobalLock(), TEST_DATA_SOURCE_NAME);
+        waitDataSourceIsAvailable();
+    }
 
     @Before
-    public void setUp() throws Exception {
-        mWmMock = Mockito.mock(WindowManagerService.class);
-        Mockito.doNothing().when(mWmMock).dumpDebugLocked(Mockito.any(), Mockito.anyInt());
-
-        mChoreographer = Mockito.mock(Choreographer.class);
-
-        mWindowTracing = new WindowTracingPerfetto(mWmMock, mChoreographer,
-                new WindowManagerGlobalLock());
-
-        mWriter = new ResultWriter()
-            .forScenario(new ScenarioBuilder()
-                    .forClass(createTempFile("temp", "").getName()).build())
-            .withOutputDir(createTempDirectory("temp").toFile())
-            .setRunComplete();
+    public void setUp() throws IOException {
+        Mockito.clearInvocations(sWmMock);
     }
 
     @After
-    public void tearDown() throws Exception {
+    public void tearDown() throws IOException {
         stopTracing();
     }
 
     @Test
     public void isEnabled_returnsFalseByDefault() {
-        assertFalse(mWindowTracing.isEnabled());
+        assertFalse(sWindowTracing.isEnabled());
     }
 
     @Test
-    public void isEnabled_returnsTrueAfterStartThenFalseAfterStop() {
+    public void isEnabled_returnsTrueAfterStartThenFalseAfterStop() throws IOException {
         startTracing(false);
-        assertTrue(mWindowTracing.isEnabled());
+        assertTrue(sWindowTracing.isEnabled());
 
         stopTracing();
-        assertFalse(mWindowTracing.isEnabled());
+        assertFalse(sWindowTracing.isEnabled());
     }
 
     @Test
     public void trace_ignoresLogStateCalls_ifTracingIsDisabled() {
-        mWindowTracing.logState("where");
-        verifyZeroInteractions(mWmMock);
+        sWindowTracing.logState("where");
+        verifyZeroInteractions(sWmMock);
     }
 
     @Test
-    public void trace_writesInitialStateSnapshot_whenTracingStarts() throws Exception {
+    public void trace_writesInitialStateSnapshot_whenTracingStarts() {
         startTracing(false);
-        verify(mWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
+        verify(sWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
     }
 
     @Test
-    public void trace_writesStateSnapshot_onLogStateCall() throws Exception {
+    public void trace_writesStateSnapshot_onLogStateCall() {
         startTracing(false);
-        mWindowTracing.logState("where");
-        verify(mWmMock, times(2)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
+        sWindowTracing.logState("where");
+        verify(sWmMock, times(2)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
     }
 
     @Test
-    public void dump_writesOneSingleStateSnapshot() throws Exception {
+    public void dump_writesOneSingleStateSnapshot() {
         startTracing(true);
-        mWindowTracing.logState("where");
-        verify(mWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
+        sWindowTracing.logState("where");
+        verify(sWmMock, times(1)).dumpDebugLocked(any(), eq(WindowTracingLogLevel.ALL));
     }
 
     private void startTracing(boolean isDump) {
         if (isDump) {
             mTraceMonitor = PerfettoTraceMonitor
                     .newBuilder()
-                    .enableWindowManagerDump()
+                    .enableWindowManagerDump(TEST_DATA_SOURCE_NAME)
                     .build();
         } else {
             mTraceMonitor = PerfettoTraceMonitor
                     .newBuilder()
-                    .enableWindowManagerTrace(LogFrequency.LOG_FREQUENCY_TRANSACTION)
+                    .enableWindowManagerTrace(LogFrequency.LOG_FREQUENCY_TRANSACTION,
+                            TEST_DATA_SOURCE_NAME)
                     .build();
         }
         mTraceMonitor.start();
     }
 
-    private void stopTracing() {
+    private void stopTracing() throws IOException {
         if (mTraceMonitor == null || !mTraceMonitor.isEnabled()) {
             return;
         }
-        mTraceMonitor.stop(mWriter);
+
+        ResultWriter writer = new ResultWriter()
+                .forScenario(new ScenarioBuilder()
+                        .forClass(createTempFile("temp", "").getName()).build())
+                .withOutputDir(createTempDirectory("temp").toFile())
+                .setRunComplete();
+
+        mTraceMonitor.stop(writer);
+    }
+
+    private static void waitDataSourceIsAvailable() {
+        final int timeoutMs = 10000;
+        final int busyWaitIntervalMs = 100;
+
+        int elapsedMs = 0;
+
+        while (!isDataSourceAvailable()) {
+            try {
+                Thread.sleep(busyWaitIntervalMs);
+                elapsedMs += busyWaitIntervalMs;
+                if (elapsedMs >= timeoutMs) {
+                    throw new RuntimeException("Data source didn't become available."
+                            + " Waited for: " + timeoutMs + " ms");
+                }
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private static boolean isDataSourceAvailable() {
+        byte[] proto = executeShellCommand("perfetto --query-raw");
+
+        try {
+            TracingServiceState state = TracingServiceState.parseFrom(proto);
+
+            Optional<Integer> producerId = Optional.empty();
+
+            for (TracingServiceState.Producer producer : state.getProducersList()) {
+                if (producer.getPid() == android.os.Process.myPid()) {
+                    producerId = Optional.of(producer.getId());
+                    break;
+                }
+            }
+
+            if (producerId.isEmpty()) {
+                return false;
+            }
+
+            for (TracingServiceState.DataSource ds : state.getDataSourcesList()) {
+                if (ds.getDsDescriptor().getName().equals(TEST_DATA_SOURCE_NAME)
+                        && ds.getProducerId() == producerId.get()) {
+                    return true;
+                }
+            }
+        } catch (InvalidProtocolBufferException e) {
+            throw new RuntimeException(e);
+        }
+
+        return false;
+    }
+
+    private static byte[] executeShellCommand(String command) {
+        try {
+            ParcelFileDescriptor fd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .executeShellCommand(command);
+            FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(fd);
+            return is.readAllBytes();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
     }
 }
diff --git a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
index 579fda3..a0f01bd 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteTransmissionUpdateCallback.aidl
@@ -50,4 +50,11 @@
      *                     Satellite location is based on magnetic north direction.
      */
     void onSatellitePositionChanged(in PointingInfo pointingInfo);
+
+    /**
+     * Called when framework receives a request to send a datagram.
+     *
+     * @param datagramType The type of the requested datagram.
+     */
+    void onSendDatagramRequested(int datagramType);
 }
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 284e2bd..90dae3b 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -1220,6 +1220,12 @@
                                         () -> callback.onReceiveDatagramStateChanged(
                                                 state, receivePendingCount, errorCode)));
                             }
+
+                            @Override
+                            public void onSendDatagramRequested(int datagramType) {
+                                executor.execute(() -> Binder.withCleanCallingIdentity(
+                                        () -> callback.onSendDatagramRequested(datagramType)));
+                            }
                         };
                 sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
                 telephony.startSatelliteTransmissionUpdates(errorCallback, internalCallback);
diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
index d8bd662..046ae5f 100644
--- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
@@ -75,4 +75,13 @@
     void onReceiveDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount,
             @SatelliteManager.SatelliteResult int errorCode);
+
+    /**
+     * Called when framework receives a request to send a datagram.
+     *
+     * @param datagramType The type of the requested datagram.
+     *
+     * @hide
+     */
+    default void onSendDatagramRequested(@SatelliteManager.DatagramType int datagramType) {}
 }
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 67825d2..095c819 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
@@ -41,7 +41,7 @@
  * Transitions: From A launch a trampoline Activity T, T launches secondary Activity B and finishes
  * itself, end up in split A|B.
  *
- * To run this test: `atest FlickerTestsOther:OpenTrampolineActivityTest`
+ * To run this test: `atest FlickerTestsActivityEmbedding:OpenTrampolineActivityTest`
  */
 @FlakyTest(bugId = 341209752)
 @RequiresDevice
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 4a675be..0bcd2f3 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,6 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
+import android.os.SystemClock
 import android.tools.PlatformConsts
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.helpers.FIND_TIMEOUT
@@ -25,6 +26,7 @@
 import android.tools.traces.parsers.toFlickerComponent
 import android.util.Log
 import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.Until
 import androidx.window.extensions.WindowExtensions
 import androidx.window.extensions.WindowExtensionsProvider
@@ -83,6 +85,7 @@
      * activity and finish itself.
      */
     fun launchTrampolineActivity(wmHelper: WindowManagerStateHelper) {
+        scrollToBottom()
         val launchButton =
             uiDevice.wait(
                 Until.findObject(By.res(packageName, "launch_trampoline_button")),
@@ -210,6 +213,7 @@
      * placeholder secondary activity based on the placeholder rule.
      */
     fun launchPlaceholderSplitRTL(wmHelper: WindowManagerStateHelper) {
+        scrollToBottom()
         val launchButton =
             uiDevice.wait(
                 Until.findObject(By.res(packageName, "launch_placeholder_split_rtl_button")),
@@ -224,6 +228,21 @@
             .waitForAndVerify()
     }
 
+    /**
+     * Scrolls to the bottom of the launch options. This is needed if the launch button is at the
+     * bottom. Otherwise the click may trigger touch on navBar.
+     */
+    private fun scrollToBottom() {
+        val launchOptionsList = uiDevice.wait(
+            Until.findObject(By.res(packageName, "launch_options_list")),
+            FIND_TIMEOUT
+        )
+        requireNotNull(launchOptionsList) { "Unable to find the list of launch options" }
+        launchOptionsList.scrollUntil(Direction.DOWN, Until.scrollFinished(Direction.DOWN))
+        // Wait a bit after scrolling, otherwise the immediate click may not be treated as "click".
+        SystemClock.sleep(1000L)
+    }
+
     companion object {
         private const val TAG = "ActivityEmbeddingAppHelper"
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index 917aec1..939ba81 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -21,8 +21,10 @@
     android:background="@android:color/holo_orange_light">
 
     <LinearLayout
+        android:id="@+id/launch_options_list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:paddingBottom="48dp"
         android:orientation="vertical">
 
         <Button
diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
new file mode 100644
index 0000000..072341d
--- /dev/null
+++ b/tests/Input/src/android/hardware/input/KeyGestureEventHandlerTest.kt
@@ -0,0 +1,236 @@
+/*
+ * 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.content.Context
+import android.content.ContextWrapper
+import android.os.Handler
+import android.os.IBinder
+import android.os.test.TestLooper
+import android.platform.test.annotations.Presubmit
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.KeyEvent
+import androidx.test.core.app.ApplicationProvider
+import com.android.server.testutils.any
+import org.junit.After
+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
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnitRunner
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertNull
+import kotlin.test.fail
+
+/**
+ * Tests for [InputManager.KeyGestureEventHandler].
+ *
+ * Build/Install/Run:
+ * atest InputTests:KeyGestureEventHandlerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner::class)
+class KeyGestureEventHandlerTest {
+
+    companion object {
+        const val DEVICE_ID = 1
+        val HOME_GESTURE_EVENT = KeyGestureEvent.Builder()
+            .setDeviceId(DEVICE_ID)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H))
+            .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+            .build()
+        val BACK_GESTURE_EVENT = KeyGestureEvent.Builder()
+            .setDeviceId(DEVICE_ID)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_DEL))
+            .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+            .build()
+    }
+
+    @get:Rule
+    val rule = SetFlagsRule()
+
+    private val testLooper = TestLooper()
+    private var registeredListener: IKeyGestureHandler? = null
+    private lateinit var context: Context
+    private lateinit var inputManager: InputManager
+    private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
+
+    @Mock
+    private lateinit var iInputManagerMock: IInputManager
+
+    @Before
+    fun setUp() {
+        context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+        inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock)
+        inputManager = InputManager(context)
+        `when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
+                .thenReturn(inputManager)
+
+        // Handle key gesture handler registration.
+        doAnswer {
+            val listener = it.getArgument(0) as IKeyGestureHandler
+            if (registeredListener != null &&
+                    registeredListener!!.asBinder() != listener.asBinder()) {
+                // There can only be one registered key gesture handler per process.
+                fail("Trying to register a new listener when one already exists")
+            }
+            registeredListener = listener
+            null
+        }.`when`(iInputManagerMock).registerKeyGestureHandler(any())
+
+        // Handle key gesture handler being unregistered.
+        doAnswer {
+            val listener = it.getArgument(0) as IKeyGestureHandler
+            if (registeredListener == null ||
+                    registeredListener!!.asBinder() != listener.asBinder()) {
+                fail("Trying to unregister a listener that is not registered")
+            }
+            registeredListener = null
+            null
+        }.`when`(iInputManagerMock).unregisterKeyGestureHandler(any())
+    }
+
+    @After
+    fun tearDown() {
+        if (this::inputManagerGlobalSession.isInitialized) {
+            inputManagerGlobalSession.close()
+        }
+    }
+
+    private fun handleKeyGestureEvent(event: KeyGestureEvent) {
+        val eventToSend = AidlKeyGestureEvent()
+        eventToSend.deviceId = event.deviceId
+        eventToSend.keycodes = event.keycodes
+        eventToSend.modifierState = event.modifierState
+        eventToSend.gestureType = event.keyGestureType
+        eventToSend.action = event.action
+        eventToSend.displayId = event.displayId
+        eventToSend.flags = event.flags
+        registeredListener!!.handleKeyGesture(eventToSend, null)
+    }
+
+    @Test
+    fun testHandlerHasCorrectGestureNotified() {
+        var callbackCount = 0
+
+        // Add a key gesture event listener
+        inputManager.registerKeyGestureEventHandler(KeyGestureHandler { event, _ ->
+            assertEquals(HOME_GESTURE_EVENT, event)
+            callbackCount++
+            true
+        })
+
+        // Request handling for key gesture event will notify the handler.
+        handleKeyGestureEvent(HOME_GESTURE_EVENT)
+        assertEquals(1, callbackCount)
+    }
+
+    @Test
+    fun testAddingHandlersRegistersInternalCallbackHandler() {
+        // Set up two callbacks.
+        val callback1 = KeyGestureHandler { _, _ -> false }
+        val callback2 = KeyGestureHandler { _, _ -> false }
+
+        assertNull(registeredListener)
+
+        // Adding the handler should register the callback with InputManagerService.
+        inputManager.registerKeyGestureEventHandler(callback1)
+        assertNotNull(registeredListener)
+
+        // Adding another handler should not register new internal listener.
+        val currListener = registeredListener
+        inputManager.registerKeyGestureEventHandler(callback2)
+        assertEquals(currListener, registeredListener)
+    }
+
+    @Test
+    fun testRemovingHandlersUnregistersInternalCallbackHandler() {
+        // Set up two callbacks.
+        val callback1 = KeyGestureHandler { _, _ -> false }
+        val callback2 = KeyGestureHandler { _, _ -> false }
+
+        inputManager.registerKeyGestureEventHandler(callback1)
+        inputManager.registerKeyGestureEventHandler(callback2)
+
+        // Only removing all handlers should remove the internal callback
+        inputManager.unregisterKeyGestureEventHandler(callback1)
+        assertNotNull(registeredListener)
+        inputManager.unregisterKeyGestureEventHandler(callback2)
+        assertNull(registeredListener)
+    }
+
+    @Test
+    fun testMultipleHandlers() {
+        // Set up two callbacks.
+        var callbackCount1 = 0
+        var callbackCount2 = 0
+        // Handler 1 captures all home gestures
+        val callback1 = KeyGestureHandler { event, _ ->
+            callbackCount1++
+            event.keyGestureType == KeyGestureEvent.KEY_GESTURE_TYPE_HOME
+        }
+        // Handler 2 captures all gestures
+        val callback2 = KeyGestureHandler { _, _ ->
+            callbackCount2++
+            true
+        }
+
+        // Add both key gesture event handlers
+        inputManager.registerKeyGestureEventHandler(callback1)
+        inputManager.registerKeyGestureEventHandler(callback2)
+
+        // Request handling for key gesture event, should notify callbacks in order. So, only the
+        // first handler should receive a callback since it captures the event.
+        handleKeyGestureEvent(HOME_GESTURE_EVENT)
+        assertEquals(1, callbackCount1)
+        assertEquals(0, callbackCount2)
+
+        // Second handler should receive the event since the first handler doesn't capture the event
+        handleKeyGestureEvent(BACK_GESTURE_EVENT)
+        assertEquals(2, callbackCount1)
+        assertEquals(1, callbackCount2)
+
+        inputManager.unregisterKeyGestureEventHandler(callback1)
+        // Request handling for key gesture event, should still trigger callback2 but not callback1.
+        handleKeyGestureEvent(HOME_GESTURE_EVENT)
+        assertEquals(2, callbackCount1)
+        assertEquals(2, callbackCount2)
+    }
+
+    inner class KeyGestureHandler(
+        private var handler: (event: KeyGestureEvent, token: IBinder?) -> Boolean
+    ) : InputManager.KeyGestureEventHandler {
+
+        override fun handleKeyGestureEvent(
+            event: KeyGestureEvent,
+            focusedToken: IBinder?
+        ): Boolean {
+            return handler(event, focusedToken)
+        }
+
+        override fun isKeyGestureSupported(gestureType: Int): Boolean {
+            return true
+        }
+    }
+}
diff --git a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt
index 14aac66..ca9de60 100644
--- a/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt
+++ b/tests/Input/src/android/hardware/input/KeyGestureEventListenerTest.kt
@@ -53,12 +53,12 @@
 
     companion object {
         const val DEVICE_ID = 1
-        val HOME_GESTURE_EVENT = KeyGestureEvent(
-            DEVICE_ID,
-            intArrayOf(KeyEvent.KEYCODE_H),
-            KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
-            KeyGestureEvent.KEY_GESTURE_TYPE_HOME
-        )
+        val HOME_GESTURE_EVENT = KeyGestureEvent.Builder()
+            .setDeviceId(DEVICE_ID)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H))
+            .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+            .build()
     }
 
     @get:Rule
@@ -114,12 +114,15 @@
     }
 
     private fun notifyKeyGestureEvent(event: KeyGestureEvent) {
-        registeredListener!!.onKeyGestureEvent(
-            event.deviceId,
-            event.keycodes,
-            event.modifierState,
-            event.keyGestureType
-        )
+        val eventToSend = AidlKeyGestureEvent()
+        eventToSend.deviceId = event.deviceId
+        eventToSend.keycodes = event.keycodes
+        eventToSend.modifierState = event.modifierState
+        eventToSend.gestureType = event.keyGestureType
+        eventToSend.action = event.action
+        eventToSend.displayId = event.displayId
+        eventToSend.flags = event.flags
+        registeredListener!!.onKeyGestureEvent(eventToSend)
     }
 
     @Test
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 3f611e0..e126797 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -18,18 +18,28 @@
 
 import android.content.Context
 import android.content.ContextWrapper
+import android.hardware.input.IInputManager
+import android.hardware.input.AidlKeyGestureEvent
 import android.hardware.input.IKeyGestureEventListener
+import android.hardware.input.IKeyGestureHandler
+import android.hardware.input.InputManager
+import android.hardware.input.InputManagerGlobal
 import android.hardware.input.KeyGestureEvent
+import android.os.IBinder
+import android.os.Process
+import android.os.test.TestLooper
 import android.platform.test.annotations.Presubmit
+import android.view.InputDevice
 import android.view.KeyEvent
 import androidx.test.core.app.ApplicationProvider
+import com.android.internal.util.FrameworkStatsLog
+import com.android.modules.utils.testing.ExtendedMockitoRule
 import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNull
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
+import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.junit.MockitoJUnit
 
 /**
  * Tests for {@link KeyGestureController}.
@@ -41,26 +51,55 @@
 class KeyGestureControllerTests {
 
     companion object {
-        val DEVICE_ID = 1
-        val HOME_GESTURE_EVENT = KeyGestureEvent(
-            DEVICE_ID,
-            intArrayOf(KeyEvent.KEYCODE_H),
-            KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
-            KeyGestureEvent.KEY_GESTURE_TYPE_HOME
-        )
+        const val DEVICE_ID = 1
+        val HOME_GESTURE_COMPLETE_EVENT = KeyGestureEvent.Builder()
+            .setDeviceId(DEVICE_ID)
+            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_H))
+            .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON)
+            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+            .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+            .build()
     }
 
-    @get:Rule
-    val rule = MockitoJUnit.rule()!!
+    @JvmField
+    @Rule
+    val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
+        .mockStatic(FrameworkStatsLog::class.java).build()!!
 
+    @Mock
+    private lateinit var iInputManager: IInputManager
+
+    private var currentPid = 0
     private lateinit var keyGestureController: KeyGestureController
     private lateinit var context: Context
-    private var lastEvent: KeyGestureEvent? = null
+    private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
+    private lateinit var testLooper: TestLooper
+    private var events = mutableListOf<KeyGestureEvent>()
 
     @Before
     fun setup() {
         context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
-        keyGestureController = KeyGestureController()
+        inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
+        setupInputDevices()
+        testLooper = TestLooper()
+        currentPid = Process.myPid()
+        keyGestureController = KeyGestureController(context, testLooper.looper)
+    }
+
+    private fun setupInputDevices() {
+        val inputManager = InputManager(context)
+        Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
+            .thenReturn(inputManager)
+
+        val keyboardDevice = InputDevice.Builder().setId(DEVICE_ID).build()
+        Mockito.`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID))
+        Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice)
+    }
+
+    private fun notifyHomeGestureCompleted() {
+        keyGestureController.notifyKeyGestureCompleted(DEVICE_ID, intArrayOf(KeyEvent.KEYCODE_H),
+            KeyEvent.META_META_ON or KeyEvent.META_META_LEFT_ON,
+            KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
     }
 
     @Test
@@ -69,28 +108,97 @@
 
         // Register key gesture event listener
         keyGestureController.registerKeyGestureEventListener(listener, 0)
-        keyGestureController.onKeyGestureEvent(HOME_GESTURE_EVENT)
+        notifyHomeGestureCompleted()
+        testLooper.dispatchAll()
         assertEquals(
-            "Listener should get callback on key gesture event",
-            HOME_GESTURE_EVENT,
-            lastEvent!!
+            "Listener should get callbacks on key gesture event completed",
+            1,
+            events.size
+        )
+        assertEquals(
+            "Listener should get callback for key gesture complete event",
+            HOME_GESTURE_COMPLETE_EVENT,
+            events[0]
         )
 
         // Unregister listener
-        lastEvent = null
+        events.clear()
         keyGestureController.unregisterKeyGestureEventListener(listener, 0)
-        keyGestureController.onKeyGestureEvent(HOME_GESTURE_EVENT)
-        assertNull("Listener should not get callback after being unregistered", lastEvent)
+        notifyHomeGestureCompleted()
+        testLooper.dispatchAll()
+        assertEquals(
+            "Listener should not get callback after being unregistered",
+            0,
+            events.size
+        )
+    }
+
+    @Test
+    fun testKeyGestureEvent_multipleGestureHandlers() {
+        // Set up two callbacks.
+        var callbackCount1 = 0
+        var callbackCount2 = 0
+        var selfCallback = 0
+        val externalHandler1 = KeyGestureHandler { _, _ ->
+            callbackCount1++;
+            true
+        }
+        val externalHandler2 = KeyGestureHandler { _, _ ->
+            callbackCount2++;
+            true
+        }
+        val selfHandler = KeyGestureHandler { _, _ ->
+            selfCallback++;
+            false
+        }
+
+        // Register key gesture handler: External process (last in priority)
+        keyGestureController.registerKeyGestureHandler(externalHandler1, currentPid + 1)
+
+        // Register key gesture handler: External process (second in priority)
+        keyGestureController.registerKeyGestureHandler(externalHandler2, currentPid - 1)
+
+        // Register key gesture handler: Self process (first in priority)
+        keyGestureController.registerKeyGestureHandler(selfHandler, currentPid)
+
+        keyGestureController.handleKeyGesture(/* deviceId = */ 0, intArrayOf(KeyEvent.KEYCODE_HOME),
+            /* modifierState = */ 0, KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+            KeyGestureEvent.ACTION_GESTURE_COMPLETE, /* displayId */ 0,
+            /* focusedToken = */ null, /* flags = */ 0
+        )
+
+        assertEquals(
+            "Self handler should get callbacks first",
+            1,
+            selfCallback
+        )
+        assertEquals(
+            "Higher priority handler should get callbacks first",
+            1,
+            callbackCount2
+        )
+        assertEquals(
+            "Lower priority handler should not get callbacks if already handled",
+            0,
+            callbackCount1
+        )
     }
 
     inner class KeyGestureEventListener : IKeyGestureEventListener.Stub() {
-        override fun onKeyGestureEvent(
-                deviceId: Int,
-                keycodes: IntArray,
-                modifierState: Int,
-                gestureType: Int
-        ) {
-            lastEvent = KeyGestureEvent(deviceId, keycodes, modifierState, gestureType)
+        override fun onKeyGestureEvent(event: AidlKeyGestureEvent) {
+            events.add(KeyGestureEvent(event))
+        }
+    }
+
+    inner class KeyGestureHandler(
+        private var handler: (event: AidlKeyGestureEvent, token: IBinder?) -> Boolean
+    ) : IKeyGestureHandler.Stub() {
+        override fun handleKeyGesture(event: AidlKeyGestureEvent, token: IBinder?): Boolean {
+            return handler(event, token)
+        }
+
+        override fun isKeyGestureSupported(gestureType: Int): Boolean {
+            return true
         }
     }
 }
\ No newline at end of file
diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
index 99e04cc..0719686 100644
--- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
+++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
@@ -85,8 +85,8 @@
         when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
 
         mTouchpadDebugView = new TouchpadDebugView(mTestableContext, TOUCHPAD_DEVICE_ID,
-                new TouchpadHardwareProperties.Builder(500f, 500f, 500f,
-                        500f, 0f, 0f, -5f, 5f, (short) 10, true,
+                new TouchpadHardwareProperties.Builder(0f, 0f, 500f,
+                        500f, 45f, 47f, -4f, 5f, (short) 10, true,
                         true).build());
 
         mTouchpadDebugView.measure(
diff --git a/tests/permission/Android.bp b/tests/permission/Android.bp
index d80eaeb..1a08f99 100644
--- a/tests/permission/Android.bp
+++ b/tests/permission/Android.bp
@@ -25,3 +25,10 @@
     platform_apis: true,
     test_suites: ["device-tests"],
 }
+
+test_module_config {
+    name: "FrameworkPermissionTests_Presubmit",
+    base: "FrameworkPermissionTests",
+    test_suites: ["device-tests"],
+    include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index ea77b8d..4920f7b4 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -5,6 +5,10 @@
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
     default_applicable_licenses: ["frameworks_base_license"],
+
+    // OWNER: g/ravenwood
+    // Bug component: 25698
+    default_team: "trendy_team_framework_backstage_power",
 }
 
 // Visibility only for ravenwood prototype uses.
diff --git a/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
index f5af99e..b79563f 100644
--- a/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
+++ b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
@@ -103,3 +103,26 @@
 
     return fix.build()
 }
+
+/**
+ * PermissionAnnotationDetector uses this method to determine whether a specific file should be
+ * checked for unannotated methods. Only files located in directories whose paths begin with one
+ * of these prefixes will be considered.
+ */
+fun isSystemServicePath(context: JavaContext): Boolean {
+    val systemServicePathPrefixes = setOf(
+        "frameworks/base/services",
+        "frameworks/base/apex",
+        "frameworks/opt/wear",
+        "packages/modules"
+    )
+
+    val filePath = context.file.path
+
+    // We perform `filePath.contains` instead of `filePath.startsWith` since getting the
+    // relative path of a source file is non-trivial. That is because `context.file.path`
+    // returns the path to where soong builds the file (i.e. /out/soong/...). Moreover, the
+    // logic to extract the relative path would need to consider several /out/soong/...
+    // locations patterns.
+    return systemServicePathPrefixes.any { filePath.contains(it) }
+}
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index 5c64697..af753e5 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -20,7 +20,6 @@
 import com.android.tools.lint.client.api.Vendor
 import com.android.tools.lint.detector.api.CURRENT_API
 import com.google.android.lint.parcel.SaferParcelChecker
-import com.google.android.lint.aidl.PermissionAnnotationDetector
 import com.google.auto.service.AutoService
 
 @AutoService(IssueRegistry::class)
@@ -38,7 +37,6 @@
         SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
         // TODO: Currently crashes due to OOM issue
         // PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
-        PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
         PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
         PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
         FeatureAutomotiveDetector.ISSUE,
diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/PermissionAnnotationDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/PermissionAnnotationDetectorTest.kt
deleted file mode 100644
index bce848a..0000000
--- a/tools/lint/framework/checks/src/test/java/com/google/android/lint/PermissionAnnotationDetectorTest.kt
+++ /dev/null
@@ -1,134 +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.google.android.lint.aidl
-
-import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestFile
-import com.android.tools.lint.checks.infrastructure.TestLintTask
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Issue
-
-@Suppress("UnstableApiUsage")
-class PermissionAnnotationDetectorTest : LintDetectorTest() {
-    override fun getDetector(): Detector = PermissionAnnotationDetector()
-
-    override fun getIssues(): List<Issue> = listOf(
-        PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
-    )
-
-    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
-
-    /** No issue scenario */
-
-    fun testDoesNotDetectIssuesInCorrectScenario() {
-        lint().files(
-            java(
-            """
-            public class Foo extends IFoo.Stub {
-                @Override
-                @android.annotation.EnforcePermission("android.Manifest.permission.READ_CONTACTS")
-                public void testMethod() { }
-            }
-            """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expectClean()
-    }
-
-    fun testMissingAnnotation() {
-        lint().files(
-            java(
-            """
-            public class Bar extends IBar.Stub {
-                public void testMethod() { }
-            }
-            """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Bar.java:2: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
-                    public void testMethod() { }
-                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                1 errors, 0 warnings
-                """
-            )
-    }
-
-    fun testNoIssueWhenExtendingWithAnotherSubclass() {
-        lint().files(
-            java(
-            """
-            public class Foo extends IFoo.Stub {
-                @Override
-                @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
-                public void testMethod() { }
-                // not an AIDL method, just another method
-                public void someRandomMethod() { }
-            }
-            """).indented(),
-            java(
-            """
-            public class Baz extends Bar {
-              @Override
-              public void someRandomMethod() { }
-            }
-            """).indented(),
-            *stubs
-        )
-            .run()
-            .expectClean()
-    }
-
-    /* Stubs */
-
-    // A service with permission annotation on the method.
-    private val interfaceIFoo: TestFile = java(
-        """
-        public interface IFoo extends android.os.IInterface {
-         public static abstract class Stub extends android.os.Binder implements IFoo {
-          }
-          @Override
-          @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
-          public void testMethod();
-          @Override
-          @android.annotation.RequiresNoPermission
-          public void testMethodNoPermission();
-          @Override
-          @android.annotation.PermissionManuallyEnforced
-          public void testMethodManual();
-        }
-        """
-    ).indented()
-
-    // A service with no permission annotation.
-    private val interfaceIBar: TestFile = java(
-        """
-        public interface IBar extends android.os.IInterface {
-         public static abstract class Stub extends android.os.Binder implements IBar {
-          }
-          public void testMethod();
-        }
-        """
-    ).indented()
-
-    private val stubs = arrayOf(interfaceIFoo, interfaceIBar)
-}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
index 28eab8f..290e7be 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
@@ -20,6 +20,7 @@
 import com.android.tools.lint.client.api.Vendor
 import com.android.tools.lint.detector.api.CURRENT_API
 import com.google.android.lint.aidl.EnforcePermissionDetector
+import com.google.android.lint.aidl.PermissionAnnotationDetector
 import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
 import com.google.auto.service.AutoService
 
@@ -31,6 +32,7 @@
             EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
             EnforcePermissionDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
             EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION,
+            PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
             SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
     )
 
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
index 8777712..675a59e 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfaces.kt
@@ -20,12 +20,8 @@
  * The exemptAidlInterfaces set was generated by running ExemptAidlInterfacesGenerator on the
  * entire source tree. To reproduce the results, run generate-exempt-aidl-interfaces.sh
  * located in tools/lint/utils.
- *
- * TODO: b/363248121 - Use the exemptAidlInterfaces set inside PermissionAnnotationDetector when it
- * gets migrated to a global lint check.
  */
 val exemptAidlInterfaces = setOf(
-    "android.accessibilityservice.IAccessibilityServiceConnection",
     "android.accessibilityservice.IBrailleDisplayConnection",
     "android.accounts.IAccountAuthenticatorResponse",
     "android.accounts.IAccountManager",
@@ -663,10 +659,6 @@
     "android.uwb.IUwbOemExtensionCallback",
     "android.uwb.IUwbRangingCallbacks",
     "android.uwb.IUwbVendorUciCallback",
-    "android.view.accessibility.IAccessibilityInteractionConnectionCallback",
-    "android.view.accessibility.IAccessibilityManager",
-    "android.view.accessibility.IMagnificationConnectionCallback",
-    "android.view.accessibility.IRemoteMagnificationAnimationCallback",
     "android.view.autofill.IAutoFillManager",
     "android.view.autofill.IAutofillWindowPresenter",
     "android.view.contentcapture.IContentCaptureManager",
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionAnnotationDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
similarity index 92%
rename from tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionAnnotationDetector.kt
rename to tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
index 6b50cfd..d44c271 100644
--- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionAnnotationDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/PermissionAnnotationDetector.kt
@@ -43,8 +43,14 @@
       interfaceName: String,
       body: UBlockExpression
     ) {
+        if (!isSystemServicePath(context)) return
+
         if (context.evaluator.isAbstract(node)) return
 
+        val fullyQualifiedInterfaceName =
+            getContainingAidlInterfaceQualified(context, node) ?: return
+        if (exemptAidlInterfaces.contains(fullyQualifiedInterfaceName)) return
+
         if (AIDL_PERMISSION_ANNOTATIONS.any { node.hasAnnotation(it) }) return
 
         context.report(
@@ -80,8 +86,7 @@
             implementation = Implementation(
                 PermissionAnnotationDetector::class.java,
                 Scope.JAVA_FILE_SCOPE
-            ),
-            enabledByDefault = false
+            )
         )
     }
 }
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
new file mode 100644
index 0000000..92d0829
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class PermissionAnnotationDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector =
+        PermissionAnnotationDetector()
+
+    override fun getIssues(): List<Issue> = listOf(
+        PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
+    )
+
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    /** No issue scenario */
+
+    fun testDoesNotDetectIssuesInCorrectScenario() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Foo.java"),
+                    """
+                        package com.android.server;
+                        public class Foo extends IFoo.Stub {
+                            @Override
+                            @android.annotation.EnforcePermission("android.Manifest.permission.READ_CONTACTS")
+                            public void testMethod() { }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    fun testMissingAnnotation() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public class Bar extends IBar.Stub {
+                            public void testMethod() { }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expect(
+                """
+                src/frameworks/base/services/java/com/android/server/Bar.java:3: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
+                    public void testMethod() { }
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """
+            )
+    }
+
+    fun testMissingAnnotationInIgnoredDirectory() {
+        lint()
+            .files(
+                java(
+                    ignoredPath,
+                    """
+                        package com.android.server;
+                        public class Bar extends IBar.Stub {
+                            public void testMethod() { }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    // If this test fails, consider the following steps:
+    //   1. Pick the first entry (interface) from `exemptAidlInterfaces`.
+    //   2. Change `interfaceIExempted` to use that interface.
+    //   3. Change this test's class to extend the interface's Stub.
+    fun testMissingAnnotationAidlInterfaceExempted() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public class Bar extends android.accessibilityservice.IBrailleDisplayConnection.Stub {
+                            public void testMethod() { }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    fun testMissingAnnotationAidlInterfaceAbstractMethod() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public abstract class Bar extends IBar.Stub {
+                            public abstract void testMethod();
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    fun testNoIssueWhenExtendingWithAnotherSubclass() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Foo.java"),
+                    """
+                        package com.android.server;
+                        public class Foo extends IFoo.Stub {
+                            @Override
+                            @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+                            public void testMethod() { }
+                            // not an AIDL method, just another method
+                            public void someRandomMethod() { }
+                        }
+                    """
+                )
+                    .indented(),
+                java(
+                    createVisitedPath("Baz.java"),
+                    """
+                        package com.android.server;
+                        public class Baz extends Bar {
+                          @Override
+                          public void someRandomMethod() { }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    /* Stubs */
+
+    // A service with permission annotation on the method.
+    private val interfaceIFoo: TestFile = java(
+        """
+        public interface IFoo extends android.os.IInterface {
+         public static abstract class Stub extends android.os.Binder implements IFoo {
+          }
+          @Override
+          @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+          public void testMethod();
+          @Override
+          @android.annotation.RequiresNoPermission
+          public void testMethodNoPermission();
+          @Override
+          @android.annotation.PermissionManuallyEnforced
+          public void testMethodManual();
+        }
+        """
+    ).indented()
+
+    // A service with no permission annotation.
+    private val interfaceIBar: TestFile = java(
+        """
+        public interface IBar extends android.os.IInterface {
+         public static abstract class Stub extends android.os.Binder implements IBar {
+          }
+          public void testMethod();
+        }
+        """
+    ).indented()
+
+    // A service whose AIDL Interface is exempted.
+    private val interfaceIExempted: TestFile = java(
+        """
+        package android.accessibilityservice;
+        public interface IBrailleDisplayConnection extends android.os.IInterface {
+         public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
+          }
+          public void testMethod();
+        }
+        """
+    ).indented()
+
+    private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
+
+    private fun createVisitedPath(filename: String) =
+        "src/frameworks/base/services/java/com/android/server/$filename"
+
+    private val ignoredPath = "src/test/pkg/TestClass.java"
+}
diff --git a/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt
index 6ad223c..57c2e5a 100644
--- a/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt
+++ b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/ExemptAidlInterfacesGenerator.kt
@@ -33,12 +33,6 @@
  */
 class ExemptAidlInterfacesGenerator : AidlImplementationDetector() {
     private val targetExemptAidlInterfaceNames = mutableSetOf<String>()
-    private val systemServicePathPrefixes = setOf(
-        "frameworks/base/services",
-        "frameworks/base/apex",
-        "frameworks/opt/wear",
-        "packages/modules"
-    )
 
     // We could've improved performance by visiting classes rather than methods, however, this lint
     // check won't be run regularly, hence we've decided not to add extra overrides to
@@ -49,14 +43,7 @@
         interfaceName: String,
         body: UBlockExpression
     ) {
-        val filePath = context.file.path
-
-        // We perform `filePath.contains` instead of `filePath.startsWith` since getting the
-        // relative path of a source file is non-trivial. That is because `context.file.path`
-        // returns the path to where soong builds the file (i.e. /out/soong/...). Moreover, the
-        // logic to extract the relative path would need to consider several /out/soong/...
-        // locations patterns.
-        if (systemServicePathPrefixes.none { filePath.contains(it) }) return
+        if (!isSystemServicePath(context)) return
 
         val fullyQualifiedInterfaceName =
             getContainingAidlInterfaceQualified(context, node) ?: return