Merge "Export BatteryStats events to Atrace."
diff --git a/ApiDocs.bp b/ApiDocs.bp
index e6525c9..c87ecde 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -132,6 +132,7 @@
         "api-versions-jars-dir",
     ],
     api_levels_sdk_type: "system",
+    extensions_info_file: ":sdk-extensions-info",
 }
 
 droidstubs {
@@ -146,6 +147,7 @@
             "packages/modules/Media/apex/aidl/stable",
         ],
     },
+    extensions_info_file: ":sdk-extensions-info",
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
index 9d92e0f..b8857ec 100644
--- a/MULTIUSER_OWNERS
+++ b/MULTIUSER_OWNERS
@@ -1,5 +1,9 @@
 # OWNERS of Multiuser related files
+annabauza@google.com
 bookatz@google.com
+nykkumar@google.com
 olilan@google.com
 omakoto@google.com
+tetianameronyk@google.com
+tyk@google.com
 yamasani@google.com
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index 67acfad..c12f5b4 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -35,7 +35,6 @@
         "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -68,7 +67,6 @@
         "  $(in)",
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -84,7 +82,6 @@
 java_library_host {
     name: "platformprotos",
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -124,7 +121,6 @@
     ],
     sdk_version: "9",
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -147,7 +143,6 @@
     },
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
@@ -185,7 +180,6 @@
     ],
 
     srcs: [
-        ":framework-connectivity-protos",
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_atom_message_protos",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 32101c7..bc2e6dd 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -420,6 +420,7 @@
         "sdk-dir",
         "api-versions-jars-dir",
     ],
+    extensions_info_file: ":sdk-extensions-info",
 }
 
 droidstubs {
@@ -432,6 +433,7 @@
         "api-versions-jars-dir",
     ],
     api_levels_sdk_type: "system",
+    extensions_info_file: ":sdk-extensions-info",
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/WEAR_OWNERS b/WEAR_OWNERS
new file mode 100644
index 0000000..4f3bc27
--- /dev/null
+++ b/WEAR_OWNERS
@@ -0,0 +1,6 @@
+yzj@google.com
+shreerag@google.com
+yeabkal@google.com
+adsule@google.com
+andriyn@google.com
+yfz@google.com
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PathIteratorPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PathIteratorPerfTest.java
index 6b739bc..757b74d 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/PathIteratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/PathIteratorPerfTest.java
@@ -58,7 +58,7 @@
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         Path path = constructCircularPath(numSegments);
         while (state.keepRunning()) {
-            PathIterator iterator = path.iterator();
+            PathIterator iterator = path.getPathIterator();
             PathIterator.Segment segment = iterator.next();
             while (segment.getVerb() != VERB_DONE) {
                 segment = iterator.next();
@@ -71,7 +71,7 @@
         float[] points = new float[8];
         Path path = constructCircularPath(numSegments);
         while (state.keepRunning()) {
-            PathIterator iterator = path.iterator();
+            PathIterator iterator = path.getPathIterator();
             int verb = iterator.next(points, 0);
             while (verb != VERB_DONE) {
                 verb = iterator.next(points, 0);
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 adcd571..b995b06 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -158,11 +158,10 @@
     }
 
     @Test
-    public void timeClonedSimpleDateFormat() {
-        SimpleDateFormat sdf = new SimpleDateFormat();
+    public void timeNewSimpleDateFormat() {
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
-            sdf.clone();
+            new SimpleDateFormat();
         }
     }
 
diff --git a/apct-tests/perftests/surfaceflinger/AndroidTest.xml b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
index 53e5d99..11d1106 100644
--- a/apct-tests/perftests/surfaceflinger/AndroidTest.xml
+++ b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
@@ -49,16 +49,20 @@
         <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
         <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
 
+        <option name="instrumentation-arg" key="profiling-iterations" value="525" />
         <!-- PerfettoListener related arguments -->
         <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
         <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
 
         <!-- SimpleperfListener related arguments -->
         <option name="instrumentation-arg" key="report" value="true" />
-        <option name="instrumentation-arg" key="arguments" value="&quot;&quot;" />
+        <option name="instrumentation-arg" key="arguments" value="-g" />
         <option name="instrumentation-arg" key="events_to_record" value="instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking" />
         <option name="instrumentation-arg" key="processes_to_record" value="surfaceflinger" />
-        <option name="instrumentation-arg" key="symbols_to_report" value="&quot;android::SurfaceFlinger::commit(;android::SurfaceFlinger::composite(&quot;" />
+        <option name="instrumentation-arg" key="symbols_to_report" value="&quot;commit;android::SurfaceFlinger::commit(;composite;android::SurfaceFlinger::composite(&quot;" />
+
+        <!-- should match profiling-iterations -->
+        <option name="instrumentation-arg" key="test_iterations" value="525" />
 
         <!-- ProcLoadListener related arguments -->
         <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
index 52fb8a6..8a447bb 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
@@ -53,15 +53,17 @@
         }
     }
 
-    public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl)
-            throws InterruptedException {
-        GraphicBuffer buffer = mBufferQ.take();
-        t.setBuffer(surfaceControl,
-                HardwareBuffer.createFromGraphicBuffer(buffer),
-                null,
-                (SyncFence fence) -> {
-                    releaseCallback(fence, buffer);
-                });
+    public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl) {
+        try {
+            final GraphicBuffer buffer = mBufferQ.take();
+            t.setBuffer(surfaceControl,
+                    HardwareBuffer.createFromGraphicBuffer(buffer),
+                    null,
+                    (SyncFence fence) -> {
+                        releaseCallback(fence, buffer);
+                    });
+        } catch (InterruptedException ignore) {
+        }
     }
 
     public void releaseCallback(SyncFence fence, GraphicBuffer buffer) {
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
index 45d164c..f92c297 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Color;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
+import android.os.Bundle;
+import android.util.Log;
 import android.view.SurfaceControl;
 
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
@@ -29,6 +29,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -40,65 +41,35 @@
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class SurfaceFlingerPerfTest {
-    protected ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
+    private static final String TAG = "SurfaceFlingerPerfTest";
+    private final ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
             new ActivityScenarioRule<>(SurfaceFlingerTestActivity.class);
-    protected PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     private SurfaceFlingerTestActivity mActivity;
-    static final int BUFFER_COUNT = 2;
+    private static final int BUFFER_COUNT = 2;
+    private static final int MAX_BUFFERS = 10;
+    private static final int MAX_POSITION = 10;
+    private static final float MAX_SCALE = 2.0f;
+
+    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+    private static final String DEFAULT_PROFILING_ITERATIONS = "100";
+    private static int sProfilingIterations;
+    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
 
     @Rule
     public final RuleChain mAllRules = RuleChain
-            .outerRule(mPerfStatusReporter)
-            .around(mActivityRule);
+            .outerRule(mActivityRule);
+
+    @BeforeClass
+    public static void suiteSetup() {
+        final Bundle arguments = InstrumentationRegistry.getArguments();
+        sProfilingIterations = Integer.parseInt(
+                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+        Log.d(TAG, "suiteSetup: mProfilingIterations = " + sProfilingIterations);
+    }
+
     @Before
     public void setup() {
         mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
-    }
-
-    @After
-    public void teardown() {
-        mSurfaceControls.forEach(SurfaceControl::release);
-        mByfferTrackers.forEach(BufferFlinger::freeBuffers);
-    }
-
-
-    private ArrayList<BufferFlinger> mByfferTrackers = new ArrayList<>();
-    private BufferFlinger createBufferTracker(int color) {
-        BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
-        mByfferTrackers.add(bufferTracker);
-        return bufferTracker;
-    }
-
-    private ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
-    private SurfaceControl createSurfaceControl() throws InterruptedException {
-        SurfaceControl sc = mActivity.createChildSurfaceControl();
-        mSurfaceControls.add(sc);
-        return sc;
-    }
-
-    @Test
-    public void singleBuffer() throws Exception {
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        bufferTracker.addBuffer(t, sc);
-        t.show(sc);
-
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            bufferTracker.addBuffer(t, sc);
-            t.apply();
-        }
-    }
-
-    static int getRandomColorComponent() {
-        return new Random().nextInt(155) + 100;
-    }
-
-    @Test
-    public void multipleBuffers() throws Exception {
-        final int MAX_BUFFERS = 10;
-
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         for (int i = 0; i < MAX_BUFFERS; i++) {
             SurfaceControl sc = createSurfaceControl();
@@ -107,122 +78,120 @@
                     getRandomColorComponent()));
             bufferTracker.addBuffer(t, sc);
             t.setPosition(sc, i * 10, i * 10);
-            t.show(sc);
         }
         t.apply(true);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+    }
+
+    @After
+    public void teardown() {
+        mSurfaceControls.forEach(SurfaceControl::release);
+        mBufferTrackers.forEach(BufferFlinger::freeBuffers);
+    }
+
+    static int getRandomColorComponent() {
+        return new Random().nextInt(155) + 100;
+    }
+
+    private final ArrayList<BufferFlinger> mBufferTrackers = new ArrayList<>();
+    private BufferFlinger createBufferTracker(int color) {
+        BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
+        mBufferTrackers.add(bufferTracker);
+        return bufferTracker;
+    }
+
+    private final ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
+    private SurfaceControl createSurfaceControl() {
+        SurfaceControl sc = mActivity.createChildSurfaceControl();
+        mSurfaceControls.add(sc);
+        return sc;
+    }
+
+    @Test
+    public void singleBuffer() throws Exception {
+        for (int i = 0; i < sProfilingIterations; i++) {
+            mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
+        }
+    }
+
+    @Test
+    public void multipleBuffers() throws Exception {
+        for (int j = 0; j < sProfilingIterations; j++) {
             for (int i = 0; i < MAX_BUFFERS; i++) {
-                mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
+                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
+                mTransaction.show(mSurfaceControls.get(i));
             }
-            t.apply();
+            mTransaction.apply(true);
         }
     }
 
     @Test
     public void multipleOpaqueBuffers() throws Exception {
-        final int MAX_BUFFERS = 10;
-
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        for (int i = 0; i < MAX_BUFFERS; i++) {
-            SurfaceControl sc = createSurfaceControl();
-            BufferFlinger bufferTracker = createBufferTracker(Color.rgb(getRandomColorComponent(),
-                    getRandomColorComponent(), getRandomColorComponent()));
-            bufferTracker.addBuffer(t, sc);
-            t.setOpaque(sc, true);
-            t.setPosition(sc, i * 10, i * 10);
-            t.show(sc);
-        }
-        t.apply(true);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int j = 0; j < sProfilingIterations; j++) {
             for (int i = 0; i < MAX_BUFFERS; i++) {
-                mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
+                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
+                mTransaction.show(mSurfaceControls.get(i)).setOpaque(mSurfaceControls.get(i), true);
             }
-            t.apply();
+            mTransaction.apply(true);
         }
     }
 
     @Test
     public void geometryChanges() throws Exception {
-        final int MAX_POSITION = 10;
-        final float MAX_SCALE = 2.0f;
-
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        bufferTracker.addBuffer(t, sc);
-        t.show(sc).apply(true);
-
         int step = 0;
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             step = ++step % MAX_POSITION;
-            t.setPosition(sc, step, step);
+            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
             float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
-            t.setScale(sc, scale, scale);
-            t.apply();
+            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
         }
     }
 
     @Test
     public void geometryWithBufferChanges() throws Exception {
-        final int MAX_POSITION = 10;
-
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        bufferTracker.addBuffer(t, sc);
-        t.show(sc).apply(true);
-
         int step = 0;
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             step = ++step % MAX_POSITION;
-            t.setPosition(sc, step, step);
-            float scale = ((step * 2.0f) / MAX_POSITION) + 0.5f;
-            t.setScale(sc, scale, scale);
-            bufferTracker.addBuffer(t, sc);
-            t.apply();
+            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
+            float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
+            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
+            mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
         }
     }
 
     @Test
     public void addRemoveLayers() throws Exception {
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             SurfaceControl childSurfaceControl =  new SurfaceControl.Builder()
                     .setName("childLayer").setBLASTLayer().build();
-            bufferTracker.addBuffer(t, childSurfaceControl);
-            t.reparent(childSurfaceControl, sc);
-            t.apply();
-            t.remove(childSurfaceControl).apply();
+            mBufferTrackers.get(0).addBuffer(mTransaction, childSurfaceControl);
+            mTransaction.reparent(childSurfaceControl, mSurfaceControls.get(0));
+            mTransaction.show(childSurfaceControl).show(mSurfaceControls.get(0));
+            mTransaction.apply(true);
+            mTransaction.remove(childSurfaceControl).apply(true);
         }
     }
 
     @Test
     public void displayScreenshot() throws Exception {
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             Bitmap screenshot =
                     InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
             screenshot.recycle();
+            mTransaction.apply(true);
         }
     }
 
     @Test
     public void layerScreenshot() throws Exception {
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             Bitmap screenshot =
                     InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot(
                             mActivity.getWindow());
             screenshot.recycle();
+            mTransaction.apply(true);
         }
     }
-
 }
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
index 832a0cd..bb95659 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
@@ -22,6 +22,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.Window;
 import android.view.WindowManager;
 
 import java.util.concurrent.CountDownLatch;
@@ -38,12 +39,15 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         mTestSurfaceView = new TestSurfaceView(this);
         setContentView(mTestSurfaceView);
     }
 
-    public SurfaceControl createChildSurfaceControl() throws InterruptedException {
+    public SurfaceControl createChildSurfaceControl() {
         return mTestSurfaceView.getChildSurfaceControlHelper();
     }
 
@@ -65,8 +69,11 @@
             });
         }
 
-        public SurfaceControl getChildSurfaceControlHelper() throws InterruptedException {
-            mIsReady.await();
+        public SurfaceControl getChildSurfaceControlHelper() {
+            try {
+                mIsReady.await();
+            } catch (InterruptedException ignore) {
+            }
             SurfaceHolder holder = getHolder();
 
             // check to see if surface is valid
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index c3fc7b1..be0e025 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -235,6 +235,15 @@
     public static final String KEY_JS_HARD_CONSUMPTION_LIMIT = "js_hard_consumption_limit";
     // TODO: Add JobScheduler modifier keys
     /** @hide */
+    public static final String KEY_JS_REWARD_APP_INSTALL_INSTANT =
+            "js_reward_app_install_instant";
+    /** @hide */
+    public static final String KEY_JS_REWARD_APP_INSTALL_ONGOING =
+            "js_reward_app_install_ongoing";
+    /** @hide */
+    public static final String KEY_JS_REWARD_APP_INSTALL_MAX =
+            "js_reward_app_install_max";
+    /** @hide */
     public static final String KEY_JS_REWARD_TOP_ACTIVITY_INSTANT =
             "js_reward_top_activity_instant";
     /** @hide */
@@ -463,6 +472,12 @@
     public static final long DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES = arcToCake(250_000);
     // TODO: add JobScheduler modifier default values
     /** @hide */
+    public static final long DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES = arcToCake(408);
+    /** @hide */
+    public static final long DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES = arcToCake(0);
+    /** @hide */
+    public static final long DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES = arcToCake(4000);
+    /** @hide */
     public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
     /** @hide */
     public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES = CAKE_IN_ARC / 2;
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 40d1b4c..bd475e9 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -37,6 +37,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
+import android.content.res.Resources;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
@@ -993,69 +994,69 @@
                 "pre_idle_factor_short";
         private static final String KEY_USE_WINDOW_ALARMS = "use_window_alarms";
 
-        private static final long DEFAULT_FLEX_TIME_SHORT =
+        private long mDefaultFlexTimeShort =
                 !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
-        private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
+        private long mDefaultLightIdleAfterInactiveTimeout =
                 !COMPRESS_TIME ? 4 * 60 * 1000L : 30 * 1000L;
-        private static final long DEFAULT_LIGHT_IDLE_TIMEOUT =
+        private long mDefaultLightIdleTimeout =
                 !COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
-        private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f;
-        private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT =
+        private float mDefaultLightIdleFactor = 2f;
+        private long mDefaultLightMaxIdleTimeout =
                 !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
-        private static final long DEFAULT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
+        private long mDefaultLightIdleMaintenanceMinBudget =
                 !COMPRESS_TIME ? 1 * 60 * 1000L : 15 * 1000L;
-        private static final long DEFAULT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET =
+        private long mDefaultLightIdleMaintenanceMaxBudget =
                 !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L;
-        private static final long DEFAULT_MIN_LIGHT_MAINTENANCE_TIME =
+        private long mDefaultMinLightMaintenanceTime =
                 !COMPRESS_TIME ? 5 * 1000L : 1 * 1000L;
-        private static final long DEFAULT_MIN_DEEP_MAINTENANCE_TIME =
+        private long mDefaultMinDeepMaintenanceTime =
                 !COMPRESS_TIME ? 30 * 1000L : 5 * 1000L;
-        private static final long DEFAULT_INACTIVE_TIMEOUT =
+        private long mDefaultInactiveTimeout =
                 (30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
         private static final long DEFAULT_INACTIVE_TIMEOUT_SMALL_BATTERY =
                 (15 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
-        private static final long DEFAULT_SENSING_TIMEOUT =
+        private long mDefaultSensingTimeout =
                 !COMPRESS_TIME ? 4 * 60 * 1000L : 60 * 1000L;
-        private static final long DEFAULT_LOCATING_TIMEOUT =
+        private long mDefaultLocatingTimeout =
                 !COMPRESS_TIME ? 30 * 1000L : 15 * 1000L;
-        private static final float DEFAULT_LOCATION_ACCURACY = 20f;
-        private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT =
+        private float mDefaultLocationAccuracy = 20f;
+        private long mDefaultMotionInactiveTimeout =
                 !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L;
-        private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX =
+        private long mDefaultMotionInactiveTimeoutFlex =
                 !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
-        private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT =
+        private long mDefaultIdleAfterInactiveTimeout =
                 (30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
         private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY =
                 (15 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
-        private static final long DEFAULT_IDLE_PENDING_TIMEOUT =
+        private long mDefaultIdlePendingTimeout =
                 !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L;
-        private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT =
+        private long mDefaultMaxIdlePendingTimeout =
                 !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L;
-        private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
-        private static final long DEFAULT_QUICK_DOZE_DELAY_TIMEOUT =
+        private float mDefaultIdlePendingFactor = 2f;
+        private long mDefaultQuickDozeDelayTimeout =
                 !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L;
-        private static final long DEFAULT_IDLE_TIMEOUT =
+        private long mDefaultIdleTimeout =
                 !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L;
-        private static final long DEFAULT_MAX_IDLE_TIMEOUT =
+        private long mDefaultMaxIdleTimeout =
                 !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L;
-        private static final float DEFAULT_IDLE_FACTOR = 2f;
-        private static final long DEFAULT_MIN_TIME_TO_ALARM =
+        private float mDefaultIdleFactor = 2f;
+        private long mDefaultMinTimeToAlarm =
                 !COMPRESS_TIME ? 30 * 60 * 1000L : 6 * 60 * 1000L;
-        private static final long DEFAULT_MAX_TEMP_APP_ALLOWLIST_DURATION_MS = 5 * 60 * 1000L;
-        private static final long DEFAULT_MMS_TEMP_APP_ALLOWLIST_DURATION_MS = 60 * 1000L;
-        private static final long DEFAULT_SMS_TEMP_APP_ALLOWLIST_DURATION_MS = 20 * 1000L;
-        private static final long DEFAULT_NOTIFICATION_ALLOWLIST_DURATION_MS = 30 * 1000L;
-        private static final boolean DEFAULT_WAIT_FOR_UNLOCK = true;
-        private static final float DEFAULT_PRE_IDLE_FACTOR_LONG = 1.67f;
-        private static final float DEFAULT_PRE_IDLE_FACTOR_SHORT = .33f;
-        private static final boolean DEFAULT_USE_WINDOW_ALARMS = true;
+        private long mDefaultMaxTempAppAllowlistDurationMs = 5 * 60 * 1000L;
+        private long mDefaultMmsTempAppAllowlistDurationMs = 60 * 1000L;
+        private long mDefaultSmsTempAppAllowlistDurationMs = 20 * 1000L;
+        private long mDefaultNotificationAllowlistDurationMs = 30 * 1000L;
+        private boolean mDefaultWaitForUnlock = true;
+        private float mDefaultPreIdleFactorLong = 1.67f;
+        private float mDefaultPreIdleFactorShort = .33f;
+        private boolean mDefaultUseWindowAlarms = true;
 
         /**
          * A somewhat short alarm window size that we will tolerate for various alarm timings.
          *
          * @see #KEY_FLEX_TIME_SHORT
          */
-        public long FLEX_TIME_SHORT = DEFAULT_FLEX_TIME_SHORT;
+        public long FLEX_TIME_SHORT = mDefaultFlexTimeShort;
 
         /**
          * This is the time, after becoming inactive, that we go in to the first
@@ -1063,28 +1064,28 @@
          *
          * @see #KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
          */
-        public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT;
+        public long LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultLightIdleAfterInactiveTimeout;
 
         /**
          * This is the initial time that we will run in light idle maintenance mode.
          *
          * @see #KEY_LIGHT_IDLE_TIMEOUT
          */
-        public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT;
+        public long LIGHT_IDLE_TIMEOUT = mDefaultLightIdleTimeout;
 
         /**
          * Scaling factor to apply to the light idle mode time each time we complete a cycle.
          *
          * @see #KEY_LIGHT_IDLE_FACTOR
          */
-        public float LIGHT_IDLE_FACTOR = DEFAULT_LIGHT_IDLE_FACTOR;
+        public float LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
 
         /**
          * This is the maximum time we will stay in light idle mode.
          *
          * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
          */
-        public long LIGHT_MAX_IDLE_TIMEOUT = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT;
+        public long LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
 
         /**
          * This is the minimum amount of time we want to make available for maintenance mode
@@ -1093,7 +1094,7 @@
          *
          * @see #KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
          */
-        public long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = DEFAULT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
+        public long LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
 
         /**
          * This is the maximum amount of time we want to make available for maintenance mode
@@ -1104,7 +1105,7 @@
          *
          * @see #KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
          */
-        public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = DEFAULT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
+        public long LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget;
 
         /**
          * This is the minimum amount of time that we will stay in maintenance mode after
@@ -1115,7 +1116,7 @@
          *
          * @see #KEY_MIN_LIGHT_MAINTENANCE_TIME
          */
-        public long MIN_LIGHT_MAINTENANCE_TIME = DEFAULT_MIN_LIGHT_MAINTENANCE_TIME;
+        public long MIN_LIGHT_MAINTENANCE_TIME = mDefaultMinLightMaintenanceTime;
 
         /**
          * This is the minimum amount of time that we will stay in maintenance mode after
@@ -1125,7 +1126,7 @@
          * mode immediately.
          * @see #KEY_MIN_DEEP_MAINTENANCE_TIME
          */
-        public long MIN_DEEP_MAINTENANCE_TIME = DEFAULT_MIN_DEEP_MAINTENANCE_TIME;
+        public long MIN_DEEP_MAINTENANCE_TIME = mDefaultMinDeepMaintenanceTime;
 
         /**
          * This is the time, after becoming inactive, at which we start looking at the
@@ -1134,7 +1135,7 @@
          * the motion sensor whenever the screen is off.
          * @see #KEY_INACTIVE_TIMEOUT
          */
-        public long INACTIVE_TIMEOUT = DEFAULT_INACTIVE_TIMEOUT;
+        public long INACTIVE_TIMEOUT = mDefaultInactiveTimeout;
 
         /**
          * If we don't receive a callback from AnyMotion in this amount of time +
@@ -1143,14 +1144,14 @@
          * will be ignored.
          * @see #KEY_SENSING_TIMEOUT
          */
-        public long SENSING_TIMEOUT = DEFAULT_SENSING_TIMEOUT;
+        public long SENSING_TIMEOUT = mDefaultSensingTimeout;
 
         /**
          * This is how long we will wait to try to get a good location fix before going in to
          * idle mode.
          * @see #KEY_LOCATING_TIMEOUT
          */
-        public long LOCATING_TIMEOUT = DEFAULT_LOCATING_TIMEOUT;
+        public long LOCATING_TIMEOUT = mDefaultLocatingTimeout;
 
         /**
          * The desired maximum accuracy (in meters) we consider the location to be good enough to go
@@ -1158,7 +1159,7 @@
          * {@link #LOCATING_TIMEOUT} expires.
          * @see #KEY_LOCATION_ACCURACY
          */
-        public float LOCATION_ACCURACY = DEFAULT_LOCATION_ACCURACY;
+        public float LOCATION_ACCURACY = mDefaultLocationAccuracy;
 
         /**
          * This is the time, after seeing motion, that we wait after becoming inactive from
@@ -1166,14 +1167,14 @@
          *
          * @see #KEY_MOTION_INACTIVE_TIMEOUT
          */
-        public long MOTION_INACTIVE_TIMEOUT = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+        public long MOTION_INACTIVE_TIMEOUT = mDefaultMotionInactiveTimeout;
 
         /**
          * This is the alarm window size we will tolerate for motion detection timings.
          *
          * @see #KEY_MOTION_INACTIVE_TIMEOUT_FLEX
          */
-        public long MOTION_INACTIVE_TIMEOUT_FLEX = DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX;
+        public long MOTION_INACTIVE_TIMEOUT_FLEX = mDefaultMotionInactiveTimeoutFlex;
 
         /**
          * This is the time, after the inactive timeout elapses, that we will wait looking
@@ -1181,7 +1182,7 @@
          *
          * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
          */
-        public long IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT;
+        public long IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultIdleAfterInactiveTimeout;
 
         /**
          * This is the initial time, after being idle, that we will allow ourself to be back
@@ -1189,20 +1190,20 @@
          * idle.
          * @see #KEY_IDLE_PENDING_TIMEOUT
          */
-        public long IDLE_PENDING_TIMEOUT = DEFAULT_IDLE_PENDING_TIMEOUT;
+        public long IDLE_PENDING_TIMEOUT = mDefaultIdlePendingTimeout;
 
         /**
          * Maximum pending idle timeout (time spent running) we will be allowed to use.
          * @see #KEY_MAX_IDLE_PENDING_TIMEOUT
          */
-        public long MAX_IDLE_PENDING_TIMEOUT = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
+        public long MAX_IDLE_PENDING_TIMEOUT = mDefaultMaxIdlePendingTimeout;
 
         /**
          * Scaling factor to apply to current pending idle timeout each time we cycle through
          * that state.
          * @see #KEY_IDLE_PENDING_FACTOR
          */
-        public float IDLE_PENDING_FACTOR = DEFAULT_IDLE_PENDING_FACTOR;
+        public float IDLE_PENDING_FACTOR = mDefaultIdlePendingFactor;
 
         /**
          * This is amount of time we will wait from the point where we go into
@@ -1210,33 +1211,33 @@
          * and other current activity to finish.
          * @see #KEY_QUICK_DOZE_DELAY_TIMEOUT
          */
-        public long QUICK_DOZE_DELAY_TIMEOUT = DEFAULT_QUICK_DOZE_DELAY_TIMEOUT;
+        public long QUICK_DOZE_DELAY_TIMEOUT = mDefaultQuickDozeDelayTimeout;
 
         /**
          * This is the initial time that we want to sit in the idle state before waking up
          * again to return to pending idle and allowing normal work to run.
          * @see #KEY_IDLE_TIMEOUT
          */
-        public long IDLE_TIMEOUT = DEFAULT_IDLE_TIMEOUT;
+        public long IDLE_TIMEOUT = mDefaultIdleTimeout;
 
         /**
          * Maximum idle duration we will be allowed to use.
          * @see #KEY_MAX_IDLE_TIMEOUT
          */
-        public long MAX_IDLE_TIMEOUT = DEFAULT_MAX_IDLE_TIMEOUT;
+        public long MAX_IDLE_TIMEOUT = mDefaultMaxIdleTimeout;
 
         /**
          * Scaling factor to apply to current idle timeout each time we cycle through that state.
          * @see #KEY_IDLE_FACTOR
          */
-        public float IDLE_FACTOR = DEFAULT_IDLE_FACTOR;
+        public float IDLE_FACTOR = mDefaultIdleFactor;
 
         /**
          * This is the minimum time we will allow until the next upcoming alarm for us to
          * actually go in to idle mode.
          * @see #KEY_MIN_TIME_TO_ALARM
          */
-        public long MIN_TIME_TO_ALARM = DEFAULT_MIN_TIME_TO_ALARM;
+        public long MIN_TIME_TO_ALARM = mDefaultMinTimeToAlarm;
 
         /**
          * Max amount of time to temporarily whitelist an app when it receives a high priority
@@ -1244,48 +1245,49 @@
          *
          * @see #KEY_MAX_TEMP_APP_ALLOWLIST_DURATION_MS
          */
-        public long MAX_TEMP_APP_ALLOWLIST_DURATION_MS = DEFAULT_MAX_TEMP_APP_ALLOWLIST_DURATION_MS;
+        public long MAX_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMaxTempAppAllowlistDurationMs;
 
         /**
          * Amount of time we would like to whitelist an app that is receiving an MMS.
          * @see #KEY_MMS_TEMP_APP_ALLOWLIST_DURATION_MS
          */
-        public long MMS_TEMP_APP_ALLOWLIST_DURATION_MS = DEFAULT_MMS_TEMP_APP_ALLOWLIST_DURATION_MS;
+        public long MMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMmsTempAppAllowlistDurationMs;
 
         /**
          * Amount of time we would like to whitelist an app that is receiving an SMS.
          * @see #KEY_SMS_TEMP_APP_ALLOWLIST_DURATION_MS
          */
-        public long SMS_TEMP_APP_ALLOWLIST_DURATION_MS = DEFAULT_SMS_TEMP_APP_ALLOWLIST_DURATION_MS;
+        public long SMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultSmsTempAppAllowlistDurationMs;
 
         /**
          * Amount of time we would like to whitelist an app that is handling a
          * {@link android.app.PendingIntent} triggered by a {@link android.app.Notification}.
          * @see #KEY_NOTIFICATION_ALLOWLIST_DURATION_MS
          */
-        public long NOTIFICATION_ALLOWLIST_DURATION_MS = DEFAULT_NOTIFICATION_ALLOWLIST_DURATION_MS;
+        public long NOTIFICATION_ALLOWLIST_DURATION_MS = mDefaultNotificationAllowlistDurationMs;
 
         /**
          * Pre idle time factor use to make idle delay longer
          */
-        public float PRE_IDLE_FACTOR_LONG = DEFAULT_PRE_IDLE_FACTOR_LONG;
+        public float PRE_IDLE_FACTOR_LONG = mDefaultPreIdleFactorLong;
 
         /**
          * Pre idle time factor use to make idle delay shorter
          */
-        public float PRE_IDLE_FACTOR_SHORT = DEFAULT_PRE_IDLE_FACTOR_SHORT;
+        public float PRE_IDLE_FACTOR_SHORT = mDefaultPreIdleFactorShort;
 
-        public boolean WAIT_FOR_UNLOCK = DEFAULT_WAIT_FOR_UNLOCK;
+        public boolean WAIT_FOR_UNLOCK = mDefaultWaitForUnlock;
 
         /**
          * Whether to use window alarms. True to use window alarms (call AlarmManager.setWindow()).
          * False to use the legacy inexact alarms (call AlarmManager.set()).
          */
-        public boolean USE_WINDOW_ALARMS = DEFAULT_USE_WINDOW_ALARMS;
+        public boolean USE_WINDOW_ALARMS = mDefaultUseWindowAlarms;
 
         private final boolean mSmallBatteryDevice;
 
         public Constants() {
+            initDefault();
             mSmallBatteryDevice = ActivityManager.isSmallBatteryDevice();
             if (mSmallBatteryDevice) {
                 INACTIVE_TIMEOUT = DEFAULT_INACTIVE_TIMEOUT_SMALL_BATTERY;
@@ -1297,6 +1299,132 @@
             onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_DEVICE_IDLE));
         }
 
+        private void initDefault() {
+            final Resources res = getContext().getResources();
+
+            mDefaultFlexTimeShort = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_flex_time_short_ms),
+                    mDefaultFlexTimeShort);
+            mDefaultLightIdleAfterInactiveTimeout = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_light_after_inactive_to_ms),
+                    mDefaultLightIdleAfterInactiveTimeout);
+            mDefaultLightIdleTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_light_idle_to_ms),
+                    mDefaultLightIdleTimeout);
+            mDefaultLightIdleFactor = res.getFloat(
+                    com.android.internal.R.integer.device_idle_light_idle_factor);
+            mDefaultLightMaxIdleTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_light_max_idle_to_ms),
+                    mDefaultLightMaxIdleTimeout);
+            mDefaultLightIdleMaintenanceMinBudget = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_light_idle_maintenance_min_budget_ms
+                    ), mDefaultLightIdleMaintenanceMinBudget);
+            mDefaultLightIdleMaintenanceMaxBudget = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_light_idle_maintenance_max_budget_ms
+                    ), mDefaultLightIdleMaintenanceMaxBudget);
+            mDefaultMinLightMaintenanceTime = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_min_light_maintenance_time_ms),
+                    mDefaultMinLightMaintenanceTime);
+            mDefaultMinDeepMaintenanceTime = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_min_deep_maintenance_time_ms),
+                    mDefaultMinDeepMaintenanceTime);
+            mDefaultInactiveTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_inactive_to_ms),
+                    mDefaultInactiveTimeout);
+            mDefaultSensingTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_sensing_to_ms),
+                    mDefaultSensingTimeout);
+            mDefaultLocatingTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_locating_to_ms),
+                    mDefaultLocatingTimeout);
+            mDefaultLocationAccuracy = res.getFloat(
+                    com.android.internal.R.integer.device_idle_location_accuracy);
+            mDefaultMotionInactiveTimeout = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_motion_inactive_to_ms),
+                    mDefaultMotionInactiveTimeout);
+            mDefaultMotionInactiveTimeoutFlex = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_motion_inactive_to_flex_ms),
+                    mDefaultMotionInactiveTimeoutFlex);
+            mDefaultIdleAfterInactiveTimeout = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_idle_after_inactive_to_ms),
+                    mDefaultIdleAfterInactiveTimeout);
+            mDefaultIdlePendingTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_idle_pending_to_ms),
+                    mDefaultIdlePendingTimeout);
+            mDefaultMaxIdlePendingTimeout = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_max_idle_pending_to_ms),
+                    mDefaultMaxIdlePendingTimeout);
+            mDefaultIdlePendingFactor = res.getFloat(
+                    com.android.internal.R.integer.device_idle_idle_pending_factor);
+            mDefaultQuickDozeDelayTimeout = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_quick_doze_delay_to_ms),
+                    mDefaultQuickDozeDelayTimeout);
+            mDefaultIdleTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_idle_to_ms),
+                    mDefaultIdleTimeout);
+            mDefaultMaxIdleTimeout = getTimeout(
+                    res.getInteger(com.android.internal.R.integer.device_idle_max_idle_to_ms),
+                    mDefaultMaxIdleTimeout);
+            mDefaultIdleFactor = res.getFloat(
+                    com.android.internal.R.integer.device_idle_idle_factor);
+            mDefaultMinTimeToAlarm = getTimeout(res.getInteger(
+                    com.android.internal.R.integer.device_idle_min_time_to_alarm_ms),
+                    mDefaultMinTimeToAlarm);
+            mDefaultMaxTempAppAllowlistDurationMs = res.getInteger(
+                    com.android.internal.R.integer.device_idle_max_temp_app_allowlist_duration_ms);
+            mDefaultMmsTempAppAllowlistDurationMs = res.getInteger(
+                    com.android.internal.R.integer.device_idle_mms_temp_app_allowlist_duration_ms);
+            mDefaultSmsTempAppAllowlistDurationMs = res.getInteger(
+                    com.android.internal.R.integer.device_idle_sms_temp_app_allowlist_duration_ms);
+            mDefaultNotificationAllowlistDurationMs = res.getInteger(
+                    com.android.internal.R.integer.device_idle_notification_allowlist_duration_ms);
+            mDefaultWaitForUnlock = res.getBoolean(
+                    com.android.internal.R.bool.device_idle_wait_for_unlock);
+            mDefaultPreIdleFactorLong = res.getFloat(
+                    com.android.internal.R.integer.device_idle_pre_idle_factor_long);
+            mDefaultPreIdleFactorShort = res.getFloat(
+                    com.android.internal.R.integer.device_idle_pre_idle_factor_short);
+            mDefaultUseWindowAlarms = res.getBoolean(
+                    com.android.internal.R.bool.device_idle_use_window_alarms);
+
+            FLEX_TIME_SHORT = mDefaultFlexTimeShort;
+            LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultLightIdleAfterInactiveTimeout;
+            LIGHT_IDLE_TIMEOUT = mDefaultLightIdleTimeout;
+            LIGHT_IDLE_FACTOR = mDefaultLightIdleFactor;
+            LIGHT_MAX_IDLE_TIMEOUT = mDefaultLightMaxIdleTimeout;
+            LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = mDefaultLightIdleMaintenanceMinBudget;
+            LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = mDefaultLightIdleMaintenanceMaxBudget;
+            MIN_LIGHT_MAINTENANCE_TIME = mDefaultMinLightMaintenanceTime;
+            MIN_DEEP_MAINTENANCE_TIME = mDefaultMinDeepMaintenanceTime;
+            INACTIVE_TIMEOUT = mDefaultInactiveTimeout;
+            SENSING_TIMEOUT = mDefaultSensingTimeout;
+            LOCATING_TIMEOUT = mDefaultLocatingTimeout;
+            LOCATION_ACCURACY = mDefaultLocationAccuracy;
+            MOTION_INACTIVE_TIMEOUT = mDefaultMotionInactiveTimeout;
+            MOTION_INACTIVE_TIMEOUT_FLEX = mDefaultMotionInactiveTimeoutFlex;
+            IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultIdleAfterInactiveTimeout;
+            IDLE_PENDING_TIMEOUT = mDefaultIdlePendingTimeout;
+            MAX_IDLE_PENDING_TIMEOUT = mDefaultMaxIdlePendingTimeout;
+            IDLE_PENDING_FACTOR = mDefaultIdlePendingFactor;
+            QUICK_DOZE_DELAY_TIMEOUT = mDefaultQuickDozeDelayTimeout;
+            IDLE_TIMEOUT = mDefaultIdleTimeout;
+            MAX_IDLE_TIMEOUT = mDefaultMaxIdleTimeout;
+            IDLE_FACTOR = mDefaultIdleFactor;
+            MIN_TIME_TO_ALARM = mDefaultMinTimeToAlarm;
+            MAX_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMaxTempAppAllowlistDurationMs;
+            MMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultMmsTempAppAllowlistDurationMs;
+            SMS_TEMP_APP_ALLOWLIST_DURATION_MS = mDefaultSmsTempAppAllowlistDurationMs;
+            NOTIFICATION_ALLOWLIST_DURATION_MS = mDefaultNotificationAllowlistDurationMs;
+            WAIT_FOR_UNLOCK = mDefaultWaitForUnlock;
+            PRE_IDLE_FACTOR_LONG = mDefaultPreIdleFactorLong;
+            PRE_IDLE_FACTOR_SHORT = mDefaultPreIdleFactorShort;
+            USE_WINDOW_ALARMS = mDefaultUseWindowAlarms;
+        }
+
+        private long getTimeout(long defTimeout, long compTimeout) {
+            return (!COMPRESS_TIME || defTimeout < compTimeout) ? defTimeout : compTimeout;
+        }
+
 
         @Override
         public void onPropertiesChanged(DeviceConfig.Properties properties) {
@@ -1308,147 +1436,147 @@
                     switch (name) {
                         case KEY_FLEX_TIME_SHORT:
                             FLEX_TIME_SHORT = properties.getLong(
-                                    KEY_FLEX_TIME_SHORT, DEFAULT_FLEX_TIME_SHORT);
+                                    KEY_FLEX_TIME_SHORT, mDefaultFlexTimeShort);
                             break;
                         case KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT:
                             LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong(
                                     KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
-                                    DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+                                    mDefaultLightIdleAfterInactiveTimeout);
                             break;
                         case KEY_LIGHT_IDLE_TIMEOUT:
                             LIGHT_IDLE_TIMEOUT = properties.getLong(
-                                    KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT);
+                                    KEY_LIGHT_IDLE_TIMEOUT, mDefaultLightIdleTimeout);
                             break;
                         case KEY_LIGHT_IDLE_FACTOR:
                             LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
-                                    KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR));
+                                    KEY_LIGHT_IDLE_FACTOR, mDefaultLightIdleFactor));
                             break;
                         case KEY_LIGHT_MAX_IDLE_TIMEOUT:
                             LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(
-                                    KEY_LIGHT_MAX_IDLE_TIMEOUT, DEFAULT_LIGHT_MAX_IDLE_TIMEOUT);
+                                    KEY_LIGHT_MAX_IDLE_TIMEOUT, mDefaultLightMaxIdleTimeout);
                             break;
                         case KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET:
                             LIGHT_IDLE_MAINTENANCE_MIN_BUDGET = properties.getLong(
                                     KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET,
-                                    DEFAULT_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET);
+                                    mDefaultLightIdleMaintenanceMinBudget);
                             break;
                         case KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET:
                             LIGHT_IDLE_MAINTENANCE_MAX_BUDGET = properties.getLong(
                                     KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET,
-                                    DEFAULT_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET);
+                                    mDefaultLightIdleMaintenanceMaxBudget);
                             break;
                         case KEY_MIN_LIGHT_MAINTENANCE_TIME:
                             MIN_LIGHT_MAINTENANCE_TIME = properties.getLong(
                                     KEY_MIN_LIGHT_MAINTENANCE_TIME,
-                                    DEFAULT_MIN_LIGHT_MAINTENANCE_TIME);
+                                    mDefaultMinLightMaintenanceTime);
                             break;
                         case KEY_MIN_DEEP_MAINTENANCE_TIME:
                             MIN_DEEP_MAINTENANCE_TIME = properties.getLong(
                                     KEY_MIN_DEEP_MAINTENANCE_TIME,
-                                    DEFAULT_MIN_DEEP_MAINTENANCE_TIME);
+                                    mDefaultMinDeepMaintenanceTime);
                             break;
                         case KEY_INACTIVE_TIMEOUT:
                             final long defaultInactiveTimeout = mSmallBatteryDevice
                                     ? DEFAULT_INACTIVE_TIMEOUT_SMALL_BATTERY
-                                    : DEFAULT_INACTIVE_TIMEOUT;
+                                    : mDefaultInactiveTimeout;
                             INACTIVE_TIMEOUT = properties.getLong(
                                     KEY_INACTIVE_TIMEOUT, defaultInactiveTimeout);
                             break;
                         case KEY_SENSING_TIMEOUT:
                             SENSING_TIMEOUT = properties.getLong(
-                                    KEY_SENSING_TIMEOUT, DEFAULT_SENSING_TIMEOUT);
+                                    KEY_SENSING_TIMEOUT, mDefaultSensingTimeout);
                             break;
                         case KEY_LOCATING_TIMEOUT:
                             LOCATING_TIMEOUT = properties.getLong(
-                                    KEY_LOCATING_TIMEOUT, DEFAULT_LOCATING_TIMEOUT);
+                                    KEY_LOCATING_TIMEOUT, mDefaultLocatingTimeout);
                             break;
                         case KEY_LOCATION_ACCURACY:
                             LOCATION_ACCURACY = properties.getFloat(
-                                    KEY_LOCATION_ACCURACY, DEFAULT_LOCATION_ACCURACY);
+                                    KEY_LOCATION_ACCURACY, mDefaultLocationAccuracy);
                             break;
                         case KEY_MOTION_INACTIVE_TIMEOUT:
                             MOTION_INACTIVE_TIMEOUT = properties.getLong(
-                                    KEY_MOTION_INACTIVE_TIMEOUT, DEFAULT_MOTION_INACTIVE_TIMEOUT);
+                                    KEY_MOTION_INACTIVE_TIMEOUT, mDefaultMotionInactiveTimeout);
                             break;
                         case KEY_MOTION_INACTIVE_TIMEOUT_FLEX:
                             MOTION_INACTIVE_TIMEOUT_FLEX = properties.getLong(
                                     KEY_MOTION_INACTIVE_TIMEOUT_FLEX,
-                                    DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX);
+                                    mDefaultMotionInactiveTimeoutFlex);
                             break;
                         case KEY_IDLE_AFTER_INACTIVE_TIMEOUT:
                             final long defaultIdleAfterInactiveTimeout = mSmallBatteryDevice
                                     ? DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY
-                                    : DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT;
+                                    : mDefaultIdleAfterInactiveTimeout;
                             IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong(
                                     KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
                                     defaultIdleAfterInactiveTimeout);
                             break;
                         case KEY_IDLE_PENDING_TIMEOUT:
                             IDLE_PENDING_TIMEOUT = properties.getLong(
-                                    KEY_IDLE_PENDING_TIMEOUT, DEFAULT_IDLE_PENDING_TIMEOUT);
+                                    KEY_IDLE_PENDING_TIMEOUT, mDefaultIdlePendingTimeout);
                             break;
                         case KEY_MAX_IDLE_PENDING_TIMEOUT:
                             MAX_IDLE_PENDING_TIMEOUT = properties.getLong(
-                                    KEY_MAX_IDLE_PENDING_TIMEOUT, DEFAULT_MAX_IDLE_PENDING_TIMEOUT);
+                                    KEY_MAX_IDLE_PENDING_TIMEOUT, mDefaultMaxIdlePendingTimeout);
                             break;
                         case KEY_IDLE_PENDING_FACTOR:
                             IDLE_PENDING_FACTOR = properties.getFloat(
-                                    KEY_IDLE_PENDING_FACTOR, DEFAULT_IDLE_PENDING_FACTOR);
+                                    KEY_IDLE_PENDING_FACTOR, mDefaultIdlePendingFactor);
                             break;
                         case KEY_QUICK_DOZE_DELAY_TIMEOUT:
                             QUICK_DOZE_DELAY_TIMEOUT = properties.getLong(
-                                    KEY_QUICK_DOZE_DELAY_TIMEOUT, DEFAULT_QUICK_DOZE_DELAY_TIMEOUT);
+                                    KEY_QUICK_DOZE_DELAY_TIMEOUT, mDefaultQuickDozeDelayTimeout);
                             break;
                         case KEY_IDLE_TIMEOUT:
                             IDLE_TIMEOUT = properties.getLong(
-                                    KEY_IDLE_TIMEOUT, DEFAULT_IDLE_TIMEOUT);
+                                    KEY_IDLE_TIMEOUT, mDefaultIdleTimeout);
                             break;
                         case KEY_MAX_IDLE_TIMEOUT:
                             MAX_IDLE_TIMEOUT = properties.getLong(
-                                    KEY_MAX_IDLE_TIMEOUT, DEFAULT_MAX_IDLE_TIMEOUT);
+                                    KEY_MAX_IDLE_TIMEOUT, mDefaultMaxIdleTimeout);
                             break;
                         case KEY_IDLE_FACTOR:
-                            IDLE_FACTOR = properties.getFloat(KEY_IDLE_FACTOR, DEFAULT_IDLE_FACTOR);
+                            IDLE_FACTOR = properties.getFloat(KEY_IDLE_FACTOR, mDefaultIdleFactor);
                             break;
                         case KEY_MIN_TIME_TO_ALARM:
                             MIN_TIME_TO_ALARM = properties.getLong(
-                                    KEY_MIN_TIME_TO_ALARM, DEFAULT_MIN_TIME_TO_ALARM);
+                                    KEY_MIN_TIME_TO_ALARM, mDefaultMinTimeToAlarm);
                             break;
                         case KEY_MAX_TEMP_APP_ALLOWLIST_DURATION_MS:
                             MAX_TEMP_APP_ALLOWLIST_DURATION_MS = properties.getLong(
                                     KEY_MAX_TEMP_APP_ALLOWLIST_DURATION_MS,
-                                    DEFAULT_MAX_TEMP_APP_ALLOWLIST_DURATION_MS);
+                                    mDefaultMaxTempAppAllowlistDurationMs);
                             break;
                         case KEY_MMS_TEMP_APP_ALLOWLIST_DURATION_MS:
                             MMS_TEMP_APP_ALLOWLIST_DURATION_MS = properties.getLong(
                                     KEY_MMS_TEMP_APP_ALLOWLIST_DURATION_MS,
-                                    DEFAULT_MMS_TEMP_APP_ALLOWLIST_DURATION_MS);
+                                    mDefaultMmsTempAppAllowlistDurationMs);
                             break;
                         case KEY_SMS_TEMP_APP_ALLOWLIST_DURATION_MS:
                             SMS_TEMP_APP_ALLOWLIST_DURATION_MS = properties.getLong(
                                     KEY_SMS_TEMP_APP_ALLOWLIST_DURATION_MS,
-                                    DEFAULT_SMS_TEMP_APP_ALLOWLIST_DURATION_MS);
+                                    mDefaultSmsTempAppAllowlistDurationMs);
                             break;
                         case KEY_NOTIFICATION_ALLOWLIST_DURATION_MS:
                             NOTIFICATION_ALLOWLIST_DURATION_MS = properties.getLong(
                                     KEY_NOTIFICATION_ALLOWLIST_DURATION_MS,
-                                    DEFAULT_NOTIFICATION_ALLOWLIST_DURATION_MS);
+                                    mDefaultNotificationAllowlistDurationMs);
                             break;
                         case KEY_WAIT_FOR_UNLOCK:
                             WAIT_FOR_UNLOCK = properties.getBoolean(
-                                    KEY_WAIT_FOR_UNLOCK, DEFAULT_WAIT_FOR_UNLOCK);
+                                    KEY_WAIT_FOR_UNLOCK, mDefaultWaitForUnlock);
                             break;
                         case KEY_PRE_IDLE_FACTOR_LONG:
                             PRE_IDLE_FACTOR_LONG = properties.getFloat(
-                                    KEY_PRE_IDLE_FACTOR_LONG, DEFAULT_PRE_IDLE_FACTOR_LONG);
+                                    KEY_PRE_IDLE_FACTOR_LONG, mDefaultPreIdleFactorLong);
                             break;
                         case KEY_PRE_IDLE_FACTOR_SHORT:
                             PRE_IDLE_FACTOR_SHORT = properties.getFloat(
-                                    KEY_PRE_IDLE_FACTOR_SHORT, DEFAULT_PRE_IDLE_FACTOR_SHORT);
+                                    KEY_PRE_IDLE_FACTOR_SHORT, mDefaultPreIdleFactorShort);
                             break;
                         case KEY_USE_WINDOW_ALARMS:
                             USE_WINDOW_ALARMS = properties.getBoolean(
-                                    KEY_USE_WINDOW_ALARMS, DEFAULT_USE_WINDOW_ALARMS);
+                                    KEY_USE_WINDOW_ALARMS, mDefaultUseWindowAlarms);
                             break;
                         default:
                             Slog.e(TAG, "Unknown configuration key: " + name);
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index c0a9e67..5b61f9a 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -144,9 +144,9 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.tare.AlarmManagerEconomicPolicy;
 import com.android.server.tare.EconomyManagerInternal;
 import com.android.server.usage.AppStandbyInternal;
@@ -676,6 +676,9 @@
         private static final String KEY_TIME_TICK_ALLOWED_WHILE_IDLE =
                 "time_tick_allowed_while_idle";
 
+        private static final String KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF =
+                "delay_nonwakeup_alarms_while_screen_off";
+
         @VisibleForTesting
         static final String KEY_ALLOW_WHILE_IDLE_QUOTA = "allow_while_idle_quota";
 
@@ -743,6 +746,8 @@
 
         private static final int DEFAULT_TEMPORARY_QUOTA_BUMP = 0;
 
+        private static final boolean DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = true;
+
         // Minimum futurity of a new alarm
         public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
 
@@ -835,6 +840,9 @@
          */
         public int TEMPORARY_QUOTA_BUMP = DEFAULT_TEMPORARY_QUOTA_BUMP;
 
+        public boolean DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF =
+                DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF;
+
         private long mLastAllowWhileIdleWhitelistDuration = -1;
         private int mVersion = 0;
 
@@ -1011,6 +1019,11 @@
                             TEMPORARY_QUOTA_BUMP = properties.getInt(KEY_TEMPORARY_QUOTA_BUMP,
                                     DEFAULT_TEMPORARY_QUOTA_BUMP);
                             break;
+                        case KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF:
+                            DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF = properties.getBoolean(
+                                    KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF,
+                                    DEFAULT_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF);
+                            break;
                         default:
                             if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
                                 // The quotas need to be updated in order, so we can't just rely
@@ -1249,6 +1262,10 @@
             pw.print(KEY_TEMPORARY_QUOTA_BUMP, TEMPORARY_QUOTA_BUMP);
             pw.println();
 
+            pw.print(KEY_DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF,
+                    DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF);
+            pw.println();
+
             pw.decreaseIndent();
         }
 
@@ -4360,7 +4377,11 @@
         }
     }
 
+    @GuardedBy("mLock")
     boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
+        if (!mConstants.DELAY_NONWAKEUP_ALARMS_WHILE_SCREEN_OFF) {
+            return false;
+        }
         if (mInteractive) {
             return false;
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index 3bbc5a3..d284a99 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
@@ -69,6 +69,11 @@
      */
     private final ArraySet<JobStatus> mChangedJobs = new ArraySet<>();
 
+    @GuardedBy("mLock")
+    private Boolean mLastReportedStatsdBatteryNotLow = null;
+    @GuardedBy("mLock")
+    private Boolean mLastReportedStatsdStablePower = null;
+
     public BatteryController(JobSchedulerService service,
             FlexibilityController flexibilityController) {
         super(service);
@@ -176,12 +181,25 @@
             Slog.d(TAG, "maybeReportNewChargingStateLocked: "
                     + powerConnected + "/" + stablePower + "/" + batteryNotLow);
         }
+
+        if (mLastReportedStatsdStablePower == null
+                || mLastReportedStatsdStablePower != stablePower) {
+            logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_CHARGING, stablePower);
+            mLastReportedStatsdStablePower = stablePower;
+        }
+        if (mLastReportedStatsdBatteryNotLow == null
+                || mLastReportedStatsdBatteryNotLow != stablePower) {
+            logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_BATTERY_NOT_LOW,
+                    batteryNotLow);
+            mLastReportedStatsdBatteryNotLow = batteryNotLow;
+        }
+
         final long nowElapsed = sElapsedRealtimeClock.millis();
 
         mFlexibilityController.setConstraintSatisfied(
                 JobStatus.CONSTRAINT_CHARGING, mService.isBatteryCharging(), nowElapsed);
         mFlexibilityController.setConstraintSatisfied(
-                        JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow, nowElapsed);
+                JobStatus.CONSTRAINT_BATTERY_NOT_LOW, batteryNotLow, nowElapsed);
 
         for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
             final JobStatus ts = mTrackedTasks.valueAt(i);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index f6de109..abbe177 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -153,6 +153,8 @@
                 changed = true;
             }
             mDeviceIdleMode = enabled;
+            logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_DEVICE_NOT_DOZING,
+                    !mDeviceIdleMode);
             if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
             mDeviceIdleUpdateFunctor.prepare();
             if (enabled) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index 658b676..9c16772 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -644,7 +644,7 @@
         static final String KEY_FALLBACK_FLEXIBILITY_DEADLINE =
                 FC_CONFIG_PREFIX + "fallback_flexibility_deadline_ms";
         static final String KEY_MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS =
-                FC_CONFIG_PREFIX + "min_alarm_time_flexibility_ms";
+                FC_CONFIG_PREFIX + "min_time_between_flexibility_alarms_ms";
         static final String KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS =
                 FC_CONFIG_PREFIX + "percents_to_drop_num_flexible_constraints";
         static final String KEY_MAX_RESCHEDULED_DEADLINE_MS =
@@ -811,6 +811,12 @@
 
     @Override
     @GuardedBy("mLock")
+    public void dumpConstants(IndentingPrintWriter pw) {
+        mFcConfig.dump(pw);
+    }
+
+    @Override
+    @GuardedBy("mLock")
     public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
         pw.println("# Constraints Satisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints));
         pw.print("Satisfied Flexible Constraints: ");
@@ -821,7 +827,5 @@
         mFlexibilityTracker.dump(pw, predicate);
         pw.println();
         mFlexibilityAlarmQueue.dump(pw);
-        pw.println();
-        mFcConfig.dump(pw);
     }
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index dd06217..926cfc1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -96,6 +96,8 @@
     @Override
     public void reportNewIdleState(boolean isIdle) {
         synchronized (mLock) {
+            logDeviceWideConstraintStateToStatsd(JobStatus.CONSTRAINT_IDLE, isIdle);
+
             final long nowElapsed = sElapsedRealtimeClock.millis();
             mFlexibilityController.setConstraintSatisfied(
                     JobStatus.CONSTRAINT_IDLE, isIdle, nowElapsed);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 4320db0..999a3c0 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -170,13 +170,12 @@
      */
     private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
             | CONSTRAINT_DEADLINE
-            | CONSTRAINT_IDLE
             | CONSTRAINT_PREFETCH
             | CONSTRAINT_TARE_WEALTH
             | CONSTRAINT_TIMING_DELAY
             | CONSTRAINT_WITHIN_QUOTA;
 
-    // TODO(b/129954980)
+    // TODO(b/129954980): ensure this doesn't spam statsd, especially at boot
     private static final boolean STATS_LOG_ENABLED = false;
 
     // No override.
@@ -1982,7 +1981,7 @@
     }
 
     /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
-    private int getProtoConstraint(int constraint) {
+    static int getProtoConstraint(int constraint) {
         switch (constraint) {
             case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
                 return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
@@ -1998,10 +1997,16 @@
                 return JobServerProtoEnums.CONSTRAINT_DEADLINE;
             case CONSTRAINT_DEVICE_NOT_DOZING:
                 return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
+            case CONSTRAINT_FLEXIBLE:
+                return JobServerProtoEnums.CONSTRAINT_FLEXIBILITY;
             case CONSTRAINT_IDLE:
                 return JobServerProtoEnums.CONSTRAINT_IDLE;
+            case CONSTRAINT_PREFETCH:
+                return JobServerProtoEnums.CONSTRAINT_PREFETCH;
             case CONSTRAINT_STORAGE_NOT_LOW:
                 return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
+            case CONSTRAINT_TARE_WEALTH:
+                return JobServerProtoEnums.CONSTRAINT_TARE_WEALTH;
             case CONSTRAINT_TIMING_DELAY:
                 return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
             case CONSTRAINT_WITHIN_QUOTA:
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 2a2d602..8453e53 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -26,6 +26,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
 import com.android.server.job.StateChangedListener;
@@ -165,6 +166,15 @@
         return mService.areComponentsInPlaceLocked(jobStatus);
     }
 
+    protected void logDeviceWideConstraintStateToStatsd(int constraint, boolean satisfied) {
+        FrameworkStatsLog.write(
+                FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED,
+                JobStatus.getProtoConstraint(constraint),
+                satisfied
+                        ? FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
+                        : FrameworkStatsLog.DEVICE_WIDE_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
+    }
+
     public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
             Predicate<JobStatus> predicate);
     public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index 4fe021a..12ec9a4 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -554,6 +554,25 @@
         }
     }
 
+    @GuardedBy("mLock")
+    void reclaimAllAssetsLocked(final int userId, @NonNull final String pkgName, int regulationId) {
+        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
+        final long curBalance = ledger.getCurrentBalance();
+        if (curBalance <= 0) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.i(TAG, "Reclaiming " + cakeToString(curBalance)
+                    + " from " + appToString(userId, pkgName)
+                    + " because of " + eventToString(regulationId));
+        }
+
+        final long now = getCurrentTimeMillis();
+        recordTransactionLocked(userId, pkgName, ledger,
+                new Ledger.Transaction(now, now, regulationId, null, -curBalance, 0),
+                true);
+    }
+
     /**
      * Reclaim a percentage of unused ARCs from every app that hasn't been used recently. The
      * reclamation will not reduce an app's balance below its minimum balance as dictated by
@@ -564,7 +583,7 @@
      * @param minUnusedTimeMs The minimum amount of time (in milliseconds) that must have
      *                        transpired since the last user usage event before we will consider
      *                        reclaiming ARCs from the app.
-     * @param scaleMinBalance Whether or not to used the scaled minimum app balance. If false,
+     * @param scaleMinBalance Whether or not to use the scaled minimum app balance. If false,
      *                        this will use the constant min balance floor given by
      *                        {@link EconomicPolicy#getMinSatiatedBalance(int, String)}. If true,
      *                        this will use the scaled balance given by
@@ -603,7 +622,8 @@
                     }
                     if (toReclaim > 0) {
                         if (DEBUG) {
-                            Slog.i(TAG, "Reclaiming unused wealth! Taking " + toReclaim
+                            Slog.i(TAG, "Reclaiming unused wealth! Taking "
+                                    + cakeToString(toReclaim)
                                     + " from " + appToString(userId, pkgName));
                         }
 
@@ -667,21 +687,7 @@
      */
     @GuardedBy("mLock")
     void onAppRestrictedLocked(final int userId, @NonNull final String pkgName) {
-        final long curBalance = getBalanceLocked(userId, pkgName);
-        final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
-        if (curBalance <= minBalance) {
-            return;
-        }
-        if (DEBUG) {
-            Slog.i(TAG, "App restricted! Taking " + curBalance
-                    + " from " + appToString(userId, pkgName));
-        }
-
-        final long now = getCurrentTimeMillis();
-        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
-        recordTransactionLocked(userId, pkgName, ledger,
-                new Ledger.Transaction(now, now, REGULATION_BG_RESTRICTED, null, -curBalance, 0),
-                true);
+        reclaimAllAssetsLocked(userId, pkgName, REGULATION_BG_RESTRICTED);
     }
 
     /**
@@ -816,37 +822,18 @@
 
     @GuardedBy("mLock")
     void onPackageRemovedLocked(final int userId, @NonNull final String pkgName) {
-        reclaimAssetsLocked(userId, pkgName);
+        mScribe.discardLedgerLocked(userId, pkgName);
+        mCurrentOngoingEvents.delete(userId, pkgName);
         mBalanceThresholdAlarmQueue.removeAlarmForKey(new Package(userId, pkgName));
     }
 
-    /**
-     * Reclaims any ARCs granted to the app, making them available to other apps. Also deletes the
-     * app's ledger and stops any ongoing event tracking.
-     */
     @GuardedBy("mLock")
-    private void reclaimAssetsLocked(final int userId, @NonNull final String pkgName) {
-        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
-        if (ledger.getCurrentBalance() != 0) {
-            mScribe.adjustRemainingConsumableCakesLocked(-ledger.getCurrentBalance());
-        }
-        mScribe.discardLedgerLocked(userId, pkgName);
-        mCurrentOngoingEvents.delete(userId, pkgName);
-    }
-
-    @GuardedBy("mLock")
-    void onUserRemovedLocked(final int userId, @NonNull final List<String> pkgNames) {
-        reclaimAssetsLocked(userId, pkgNames);
+    void onUserRemovedLocked(final int userId) {
+        mScribe.discardLedgersLocked(userId);
+        mCurrentOngoingEvents.delete(userId);
         mBalanceThresholdAlarmQueue.removeAlarmsForUserId(userId);
     }
 
-    @GuardedBy("mLock")
-    private void reclaimAssetsLocked(final int userId, @NonNull final List<String> pkgNames) {
-        for (int i = 0; i < pkgNames.size(); ++i) {
-            reclaimAssetsLocked(userId, pkgNames.get(i));
-        }
-    }
-
     @VisibleForTesting
     static class TrendCalculator implements Consumer<OngoingEvent> {
         static final long WILL_NOT_CROSS_THRESHOLD = -1;
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index 22a2f51..7391bcf 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -55,12 +55,13 @@
     static final int TYPE_ACTION = 1 << SHIFT_TYPE;
     static final int TYPE_REWARD = 2 << SHIFT_TYPE;
 
-    private static final int SHIFT_POLICY = 29;
-    static final int MASK_POLICY = 0b1 << SHIFT_POLICY;
-    static final int POLICY_AM = 0 << SHIFT_POLICY;
-    static final int POLICY_JS = 1 << SHIFT_POLICY;
+    private static final int SHIFT_POLICY = 28;
+    static final int MASK_POLICY = 0b11 << SHIFT_POLICY;
+    // Reserve 0 for the base/common policy.
+    static final int POLICY_AM = 1 << SHIFT_POLICY;
+    static final int POLICY_JS = 2 << SHIFT_POLICY;
 
-    static final int MASK_EVENT = ~0 - (0b111 << SHIFT_POLICY);
+    static final int MASK_EVENT = -1 ^ (MASK_TYPE | MASK_POLICY);
 
     static final int REGULATION_BASIC_INCOME = TYPE_REGULATION | 0;
     static final int REGULATION_BIRTHRIGHT = TYPE_REGULATION | 1;
@@ -70,6 +71,7 @@
     /** App is fully restricted from running in the background. */
     static final int REGULATION_BG_RESTRICTED = TYPE_REGULATION | 5;
     static final int REGULATION_BG_UNRESTRICTED = TYPE_REGULATION | 6;
+    static final int REGULATION_FORCE_STOP = TYPE_REGULATION | 8;
 
     static final int REWARD_NOTIFICATION_SEEN = TYPE_REWARD | 0;
     static final int REWARD_NOTIFICATION_INTERACTION = TYPE_REWARD | 1;
@@ -118,6 +120,7 @@
             REWARD_NOTIFICATION_INTERACTION,
             REWARD_WIDGET_INTERACTION,
             REWARD_OTHER_USER_INTERACTION,
+            JobSchedulerEconomicPolicy.REWARD_APP_INSTALL,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface UtilityReward {
@@ -409,6 +412,8 @@
                 return "BG_RESTRICTED";
             case REGULATION_BG_UNRESTRICTED:
                 return "BG_UNRESTRICTED";
+            case REGULATION_FORCE_STOP:
+                return "FORCE_STOP";
         }
         return "UNKNOWN_REGULATION:" + Integer.toHexString(eventId);
     }
@@ -426,6 +431,8 @@
                 return "REWARD_WIDGET_INTERACTION";
             case REWARD_OTHER_USER_INTERACTION:
                 return "REWARD_OTHER_USER_INTERACTION";
+            case JobSchedulerEconomicPolicy.REWARD_APP_INSTALL:
+                return "REWARD_JOB_APP_INSTALL";
         }
         return "UNKNOWN_REWARD:" + Integer.toHexString(eventId);
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
index da544bb..fcb3e67 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
@@ -17,9 +17,12 @@
 package com.android.server.tare;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.InstallSourceInfo;
 import android.content.pm.PackageInfo;
-import android.os.UserHandle;
+import android.os.RemoteException;
 
 /** POJO to cache only the information about installed packages that TARE cares about. */
 class InstalledPackageInfo {
@@ -28,11 +31,21 @@
     public final int uid;
     public final String packageName;
     public final boolean hasCode;
+    @Nullable
+    public final String installerPackageName;
 
     InstalledPackageInfo(@NonNull PackageInfo packageInfo) {
         final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
-        this.uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
-        this.packageName = packageInfo.packageName;
-        this.hasCode = applicationInfo != null && applicationInfo.hasCode();
+        uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
+        packageName = packageInfo.packageName;
+        hasCode = applicationInfo != null && applicationInfo.hasCode();
+        InstallSourceInfo installSourceInfo = null;
+        try {
+            installSourceInfo = AppGlobals.getPackageManager().getInstallSourceInfo(packageName);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+        }
+        installerPackageName =
+                installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName();
     }
 }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index db91d5c..c13e1dd9 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -524,16 +524,23 @@
             mPackageToUidCache.add(userId, pkgName, uid);
         }
         synchronized (mLock) {
-            mPkgCache.add(userId, pkgName, new InstalledPackageInfo(packageInfo));
+            final InstalledPackageInfo ipo = new InstalledPackageInfo(packageInfo);
+            mPkgCache.add(userId, pkgName, ipo);
             mUidToPackageCache.add(uid, pkgName);
             // TODO: only do this when the user first launches the app (app leaves stopped state)
             mAgent.grantBirthrightLocked(userId, pkgName);
+            if (ipo.installerPackageName != null) {
+                mAgent.noteInstantaneousEventLocked(userId, ipo.installerPackageName,
+                        JobSchedulerEconomicPolicy.REWARD_APP_INSTALL, null);
+            }
         }
     }
 
     void onPackageForceStopped(final int userId, @NonNull final String pkgName) {
         synchronized (mLock) {
-            // TODO: reduce ARC count by some amount
+            // Remove all credits if the user force stops the app. It will slowly regain them
+            // in response to different events.
+            mAgent.reclaimAllAssetsLocked(userId, pkgName, EconomicPolicy.REGULATION_FORCE_STOP);
         }
     }
 
@@ -576,17 +583,15 @@
     void onUserRemoved(final int userId) {
         synchronized (mLock) {
             mVipOverrides.delete(userId);
-            ArrayList<String> removedPkgs = new ArrayList<>();
             final int uIdx = mPkgCache.indexOfKey(userId);
             if (uIdx >= 0) {
                 for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) {
                     final InstalledPackageInfo pkgInfo = mPkgCache.valueAt(uIdx, p);
-                    removedPkgs.add(pkgInfo.packageName);
                     mUidToPackageCache.remove(pkgInfo.uid);
                 }
             }
             mPkgCache.delete(userId);
-            mAgent.onUserRemovedLocked(userId, removedPkgs);
+            mAgent.onUserRemovedLocked(userId);
         }
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index cbb88c0..55cc352 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -43,6 +43,9 @@
 import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES;
 import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
 import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES;
 import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
 import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
 import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
@@ -85,6 +88,9 @@
 import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
 import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED;
 import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_ONGOING;
 import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
 import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
 import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
@@ -137,6 +143,8 @@
     public static final int ACTION_JOB_MIN_RUNNING = TYPE_ACTION | POLICY_JS | 9;
     public static final int ACTION_JOB_TIMEOUT = TYPE_ACTION | POLICY_JS | 10;
 
+    public static final int REWARD_APP_INSTALL = TYPE_REWARD | POLICY_JS | 0;
+
     private static final int[] COST_MODIFIERS = new int[]{
             COST_MODIFIER_CHARGING,
             COST_MODIFIER_DEVICE_IDLE,
@@ -374,6 +382,17 @@
                         getConstantAsCake(mParser, properties,
                                 KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
                                 DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
+        mRewards.put(REWARD_APP_INSTALL,
+                new Reward(REWARD_APP_INSTALL,
+                        getConstantAsCake(mParser, properties,
+                                KEY_JS_REWARD_APP_INSTALL_INSTANT,
+                                DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES),
+                        getConstantAsCake(mParser, properties,
+                                KEY_JS_REWARD_APP_INSTALL_ONGOING,
+                                DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES),
+                        getConstantAsCake(mParser, properties,
+                                KEY_JS_REWARD_APP_INSTALL_MAX,
+                                DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES)));
     }
 
     @Override
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 29478d0..bd4fd72 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -157,6 +157,12 @@
     }
 
     @GuardedBy("mIrs.getLock()")
+    void discardLedgersLocked(final int userId) {
+        mLedgers.delete(userId);
+        postWrite();
+    }
+
+    @GuardedBy("mIrs.getLock()")
     long getSatiatedConsumptionLimitLocked() {
         return mSatiatedConsumptionLimit;
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index f1c4eb4..67d711c 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -122,7 +122,7 @@
 import com.android.server.AlarmManagerInternal;
 import com.android.server.JobSchedulerBackgroundThread;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppIdleHistory.AppUsageHistory;
 
 import libcore.util.EmptyArray;
diff --git a/boot/Android.bp b/boot/Android.bp
index 3f14ebc..bb84494 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -68,6 +68,10 @@
             module: "com.android.conscrypt-bootclasspath-fragment",
         },
         {
+            apex: "com.android.healthconnect",
+            module: "com.android.healthconnect-bootclasspath-fragment",
+        },
+        {
             apex: "com.android.i18n",
             module: "i18n-bootclasspath-fragment",
         },
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 2cda57d..8b8d361 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -18,24 +18,22 @@
 
 #include "com_android_commands_hid_Device.h"
 
-#include <linux/uhid.h>
-
+#include <android-base/stringprintf.h>
+#include <android/looper.h>
 #include <fcntl.h>
 #include <inttypes.h>
-#include <unistd.h>
-#include <cstdio>
-#include <cstring>
-#include <memory>
-
-#include <android/looper.h>
 #include <jni.h>
+#include <linux/uhid.h>
 #include <log/log.h>
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
+#include <unistd.h>
 
-#include <android-base/stringprintf.h>
+#include <cstdio>
+#include <cstring>
+#include <memory>
 
 // Log debug messages about the output.
 static constexpr bool DEBUG_OUTPUT = false;
@@ -109,15 +107,15 @@
 
 void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
     JNIEnv* env = getJNIEnv();
-    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport,
-            requestId, reportId);
+    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport, requestId,
+                        reportId);
     checkAndClearException(env, "onDeviceGetReport");
 }
 
-void DeviceCallback::onDeviceSetReport(uint8_t rType,
-                                    const std::vector<uint8_t>& data) {
+void DeviceCallback::onDeviceSetReport(uint32_t id, uint8_t rType,
+                                       const std::vector<uint8_t>& data) {
     JNIEnv* env = getJNIEnv();
-    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, rType,
+    env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, id, rType,
                         toJbyteArray(env, data).get());
     checkAndClearException(env, "onDeviceSetReport");
 }
@@ -236,6 +234,14 @@
     writeEvent(mFd, ev, "UHID_GET_REPORT_REPLY");
 }
 
+void Device::sendSetReportReply(uint32_t id, bool success) const {
+    struct uhid_event ev = {};
+    ev.type = UHID_SET_REPORT_REPLY;
+    ev.u.set_report_reply.id = id;
+    ev.u.set_report_reply.err = success ? 0 : EIO;
+    writeEvent(mFd, ev, "UHID_SET_REPORT_REPLY");
+}
+
 int Device::handleEvents(int events) {
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
         ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
@@ -249,7 +255,6 @@
         mDeviceCallback->onDeviceError();
         return 0;
     }
-
     switch (ev.type) {
         case UHID_OPEN: {
             mDeviceCallback->onDeviceOpen();
@@ -271,7 +276,7 @@
                 ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
                       set_report.rnum, toString(data).c_str());
             }
-            mDeviceCallback->onDeviceSetReport(set_report.rtype, data);
+            mDeviceCallback->onDeviceSetReport(set_report.id, set_report.rtype, data);
             break;
         }
         case UHID_OUTPUT: {
@@ -347,6 +352,15 @@
     }
 }
 
+static void sendSetReportReply(JNIEnv*, jclass /* clazz */, jlong ptr, jint id, jboolean success) {
+    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
+    if (d) {
+        d->sendSetReportReply(id, success);
+    } else {
+        ALOGE("Could not send set report reply, Device* is null!");
+    }
+}
+
 static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
     if (d) {
@@ -362,6 +376,7 @@
         {"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
         {"nativeSendGetFeatureReportReply", "(JI[B)V",
          reinterpret_cast<void*>(sendGetFeatureReportReply)},
+        {"nativeSendSetReportReply", "(JIZ)V", reinterpret_cast<void*>(sendSetReportReply)},
         {"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
 };
 
@@ -376,7 +391,7 @@
     uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
             env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
     uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
-            env->GetMethodID(clazz, "onDeviceSetReport", "(B[B)V");
+            env->GetMethodID(clazz, "onDeviceSetReport", "(IB[B)V");
     uhid::gDeviceCallbackClassInfo.onDeviceOutput =
             env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
     uhid::gDeviceCallbackClassInfo.onDeviceError =
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index d10a9aa..9c6060d 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#include <memory>
-#include <vector>
-
+#include <android-base/unique_fd.h>
 #include <jni.h>
 
-#include <android-base/unique_fd.h>
+#include <memory>
+#include <vector>
 
 namespace android {
 namespace uhid {
@@ -31,7 +30,7 @@
 
     void onDeviceOpen();
     void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
-    void onDeviceSetReport(uint8_t rType, const std::vector<uint8_t>& data);
+    void onDeviceSetReport(uint32_t id, uint8_t rType, const std::vector<uint8_t>& data);
     void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data);
     void onDeviceError();
 
@@ -50,9 +49,9 @@
     ~Device();
 
     void sendReport(const std::vector<uint8_t>& report) const;
+    void sendSetReportReply(uint32_t id, bool success) const;
     void sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const;
     void close();
-
     int handleEvents(int events);
 
 private:
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 95b1e9a..0415037 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -42,7 +42,8 @@
     private static final int MSG_OPEN_DEVICE = 1;
     private static final int MSG_SEND_REPORT = 2;
     private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3;
-    private static final int MSG_CLOSE_DEVICE = 4;
+    private static final int MSG_SEND_SET_REPORT_REPLY = 4;
+    private static final int MSG_CLOSE_DEVICE = 5;
 
     // Sync with linux uhid_event_type::UHID_OUTPUT
     private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6;
@@ -56,21 +57,45 @@
     private final Map<ByteBuffer, byte[]> mOutputs;
     private final OutputStream mOutputStream;
     private long mTimeToSend;
-
     private final Object mCond = new Object();
+    /**
+     * The report id of the report received in UHID_EVENT_TYPE_SET_REPORT.
+     * Used for SET_REPORT_REPLY.
+     * This field gets overridden each time SET_REPORT is received.
+     */
+    private int mResponseId;
 
     static {
         System.loadLibrary("hidcommand_jni");
     }
 
-    private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus,
-            byte[] descriptor, DeviceCallback callback);
+    private static native long nativeOpenDevice(
+            String name,
+            int id,
+            int vid,
+            int pid,
+            int bus,
+            byte[] descriptor,
+            DeviceCallback callback);
+
     private static native void nativeSendReport(long ptr, byte[] data);
+
     private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data);
+
+    private static native void nativeSendSetReportReply(long ptr, int id, boolean success);
+
     private static native void nativeCloseDevice(long ptr);
 
-    public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor,
-            byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) {
+    public Device(
+            int id,
+            String name,
+            int vid,
+            int pid,
+            int bus,
+            byte[] descriptor,
+            byte[] report,
+            SparseArray<byte[]> featureReports,
+            Map<ByteBuffer, byte[]> outputs) {
         mId = id;
         mThread = new HandlerThread("HidDeviceHandler");
         mThread.start();
@@ -100,6 +125,17 @@
         mHandler.sendMessageAtTime(msg, mTimeToSend);
     }
 
+    public void setGetReportResponse(byte[] report) {
+        mFeatureReports.put(report[0], report);
+    }
+
+    public void sendSetReportReply(boolean success) {
+        Message msg =
+                mHandler.obtainMessage(MSG_SEND_SET_REPORT_REPLY, mResponseId, success ? 1 : 0);
+
+        mHandler.sendMessageAtTime(msg, mTimeToSend);
+    }
+
     public void addDelay(int delay) {
         mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
     }
@@ -111,7 +147,8 @@
             synchronized (mCond) {
                 mCond.wait();
             }
-        } catch (InterruptedException ignore) {}
+        } catch (InterruptedException ignore) {
+        }
     }
 
     private class DeviceHandler extends Handler {
@@ -127,8 +164,15 @@
             switch (msg.what) {
                 case MSG_OPEN_DEVICE:
                     SomeArgs args = (SomeArgs) msg.obj;
-                    mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
-                            args.argi4, (byte[]) args.arg2, new DeviceCallback());
+                    mPtr =
+                            nativeOpenDevice(
+                                    (String) args.arg1,
+                                    args.argi1,
+                                    args.argi2,
+                                    args.argi3,
+                                    args.argi4,
+                                    (byte[]) args.arg2,
+                                    new DeviceCallback());
                     pauseEvents();
                     break;
                 case MSG_SEND_REPORT:
@@ -145,6 +189,14 @@
                         Log.e(TAG, "Tried to send feature report reply to closed device.");
                     }
                     break;
+                case MSG_SEND_SET_REPORT_REPLY:
+                    if (mPtr != 0) {
+                        final boolean success = msg.arg2 == 1;
+                        nativeSendSetReportReply(mPtr, msg.arg1, success);
+                    } else {
+                        Log.e(TAG, "Tried to send set report reply to closed device.");
+                    }
+                    break;
                 case MSG_CLOSE_DEVICE:
                     if (mPtr != 0) {
                         nativeCloseDevice(mPtr);
@@ -173,14 +225,18 @@
     }
 
     private class DeviceCallback {
+
         public void onDeviceOpen() {
             mHandler.resumeEvents();
         }
 
         public void onDeviceGetReport(int requestId, int reportId) {
             if (mFeatureReports == null) {
-                Log.e(TAG, "Received GET_REPORT request for reportId=" + reportId
-                        + ", but 'feature_reports' section is not found");
+                Log.e(
+                        TAG,
+                        "Received GET_REPORT request for reportId="
+                                + reportId
+                                + ", but 'feature_reports' section is not found");
                 return;
             }
             byte[] report = mFeatureReports.get(reportId);
@@ -220,14 +276,15 @@
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
-
         }
 
         // native callback
-        public void onDeviceSetReport(byte rtype, byte[] data) {
+        public void onDeviceSetReport(int id, byte rType, byte[] data) {
+            // Used by sendSetReportReply()
+            mResponseId = id;
             // We don't need to reply for the SET_REPORT but just send it to HID output for test
             // verification.
-            sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rtype, data);
+            sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rType, data);
         }
 
         // native callback
@@ -239,7 +296,8 @@
             }
             byte[] response = mOutputs.get(ByteBuffer.wrap(data));
             if (response == null) {
-                Log.i(TAG,
+                Log.i(
+                        TAG,
                         "Requested response for output " + Arrays.toString(data) + " is not found");
                 return;
             }
diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java
index d4bf1d8..3efb797 100644
--- a/cmds/hid/src/com/android/commands/hid/Event.java
+++ b/cmds/hid/src/com/android/commands/hid/Event.java
@@ -35,6 +35,8 @@
     public static final String COMMAND_REGISTER = "register";
     public static final String COMMAND_DELAY = "delay";
     public static final String COMMAND_REPORT = "report";
+    public static final String COMMAND_SET_GET_REPORT_RESPONSE = "set_get_report_response";
+    public static final String COMMAND_SEND_SET_REPORT_REPLY = "send_set_report_reply";
 
     // These constants come from "include/uapi/linux/input.h" in the kernel
     enum Bus {
@@ -62,6 +64,7 @@
     private SparseArray<byte[]> mFeatureReports;
     private Map<ByteBuffer, byte[]> mOutputs;
     private int mDuration;
+    private Boolean mReply;
 
     public int getId() {
         return mId;
@@ -107,6 +110,10 @@
         return mDuration;
     }
 
+    public Boolean getReply() {
+        return mReply;
+    }
+
     public String toString() {
         return "Event{id=" + mId
             + ", command=" + String.valueOf(mCommand)
@@ -119,6 +126,7 @@
             + ", feature_reports=" + mFeatureReports.toString()
             + ", outputs=" + mOutputs.toString()
             + ", duration=" + mDuration
+            + ", success=" + mReply.toString()
             + "}";
     }
 
@@ -173,6 +181,10 @@
             mEvent.mDuration = duration;
         }
 
+        public void setReply(boolean success) {
+            mEvent.mReply = success;
+        }
+
         public Event build() {
             if (mEvent.mId == -1) {
                 throw new IllegalStateException("No event id");
@@ -183,6 +195,16 @@
                 if (mEvent.mDescriptor == null) {
                     throw new IllegalStateException("Device registration is missing descriptor");
                 }
+            }
+            if (COMMAND_SET_GET_REPORT_RESPONSE.equals(mEvent.mCommand)) {
+                if (mEvent.mReport == null) {
+                    throw new IllegalStateException("Report command is missing response data");
+                }
+            }
+            if (COMMAND_SEND_SET_REPORT_REPLY.equals(mEvent.mCommand)) {
+                if (mEvent.mReply == null) {
+                    throw new IllegalStateException("Reply command is missing reply");
+                }
             } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
                 if (mEvent.mDuration <= 0) {
                     throw new IllegalStateException("Delay has missing or invalid duration");
@@ -246,6 +268,9 @@
                             case "duration":
                                 eb.setDuration(readInt());
                                 break;
+                            case "success":
+                                eb.setReply(readBool());
+                                break;
                             default:
                                 mReader.skipValue();
                         }
@@ -292,6 +317,11 @@
             return Integer.decode(val);
         }
 
+        private boolean readBool() throws IOException {
+            String val = mReader.nextString();
+            return Boolean.parseBoolean(val);
+        }
+
         private Bus readBus() throws IOException {
             String val = mReader.nextString();
             return Bus.valueOf(val.toUpperCase());
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index fac0ab2..2db791fe 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -93,6 +93,10 @@
                 d.addDelay(e.getDuration());
             } else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
                 d.sendReport(e.getReport());
+            } else if (Event.COMMAND_SET_GET_REPORT_RESPONSE.equals(e.getCommand())) {
+                d.setGetReportResponse(e.getReport());
+            } else if (Event.COMMAND_SEND_SET_REPORT_REPLY.equals(e.getCommand())) {
+                d.sendSetReportReply(e.getReply());
             } else {
                 if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
                     error("Device id=" + e.getId() + " is already registered. Ignoring event.");
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 58aff42..03e714a 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -21,42 +21,51 @@
  * header                     := magic version target_crc overlay_crc fulfilled_policies
  *                               enforce_overlayable target_path overlay_path overlay_name
  *                               debug_info
- * data                       := data_header target_entry* target_inline_entry* overlay_entry*
- *                               string_pool
- * data_header                := target_entry_count target_inline_entry_count overlay_entry_count
+ * data                       := data_header target_entry* target_inline_entry*
+                                 target_inline_entry_value* config* overlay_entry* string_pool
+ * data_header                := target_entry_count target_inline_entry_count
+                                 target_inline_entry_value_count config_count overlay_entry_count
  *                               string_pool_index
  * target_entry               := target_id overlay_id
- * target_inline_entry        := target_id Res_value::size padding(1) Res_value::type
+ * target_inline_entry        := target_id start_value_index value_count
+ * target_inline_entry_value  := config_index Res_value::size padding(1) Res_value::type
+ *                               Res_value::value
+ * config                     := target_id Res_value::size padding(1) Res_value::type
  *                               Res_value::value
  * overlay_entry              := overlay_id target_id
  *
- * debug_info                 := string
- * enforce_overlayable        := <uint32_t>
- * fulfilled_policies         := <uint32_t>
- * magic                      := <uint32_t>
- * overlay_crc                := <uint32_t>
- * overlay_entry_count        := <uint32_t>
- * overlay_id                 := <uint32_t>
- * overlay_package_id         := <uint8_t>
- * overlay_name               := string
- * overlay_path               := string
- * padding(n)                 := <uint8_t>[n]
- * Res_value::size            := <uint16_t>
- * Res_value::type            := <uint8_t>
- * Res_value::value           := <uint32_t>
- * string                     := <uint32_t> <uint8_t>+ padding(n)
- * string_pool                := string
- * string_pool_index          := <uint32_t>
- * string_pool_length         := <uint32_t>
- * target_crc                 := <uint32_t>
- * target_entry_count         := <uint32_t>
- * target_inline_entry_count  := <uint32_t>
- * target_id                  := <uint32_t>
- * target_package_id          := <uint8_t>
- * target_path                := string
- * value_type                 := <uint8_t>
- * value_data                 := <uint32_t>
- * version                    := <uint32_t>
+ * debug_info                       := string
+ * enforce_overlayable              := <uint32_t>
+ * fulfilled_policies               := <uint32_t>
+ * magic                            := <uint32_t>
+ * overlay_crc                      := <uint32_t>
+ * overlay_entry_count              := <uint32_t>
+ * overlay_id                       := <uint32_t>
+ * overlay_package_id               := <uint8_t>
+ * overlay_name                     := string
+ * overlay_path                     := string
+ * padding(n)                       := <uint8_t>[n]
+ * Res_value::size                  := <uint16_t>
+ * Res_value::type                  := <uint8_t>
+ * Res_value::value                 := <uint32_t>
+ * string                           := <uint32_t> <uint8_t>+ padding(n)
+ * string_pool                      := string
+ * string_pool_index                := <uint32_t>
+ * string_pool_length               := <uint32_t>
+ * target_crc                       := <uint32_t>
+ * target_entry_count               := <uint32_t>
+ * target_inline_entry_count        := <uint32_t>
+ * target_inline_entry_value_count  := <uint32_t>
+ * config_count                     := <uint32_t>
+ * config_index                     := <uint32_t>
+ * start_value_index                := <uint32_t>
+ * value_count                      := <uint32_t>
+ * target_id                        := <uint32_t>
+ * target_package_id                := <uint8_t>
+ * target_path                      := string
+ * value_type                       := <uint8_t>
+ * value_data                       := <uint32_t>
+ * version                          := <uint32_t>
  */
 
 #ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
@@ -70,6 +79,7 @@
 #include "android-base/macros.h"
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
+#include "androidfw/ConfigDescription.h"
 #include "idmap2/ResourceContainer.h"
 #include "idmap2/ResourceMapping.h"
 
@@ -165,19 +175,27 @@
    public:
     static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream);
 
-    inline uint32_t GetTargetEntryCount() const {
+    [[nodiscard]] inline uint32_t GetTargetEntryCount() const {
       return target_entry_count;
     }
 
-    inline uint32_t GetTargetInlineEntryCount() const {
+    [[nodiscard]] inline uint32_t GetTargetInlineEntryCount() const {
       return target_entry_inline_count;
     }
 
-    inline uint32_t GetOverlayEntryCount() const {
+    [[nodiscard]] inline uint32_t GetTargetInlineEntryValueCount() const {
+      return target_entry_inline_value_count;
+    }
+
+    [[nodiscard]] inline uint32_t GetConfigCount() const {
+      return config_count;
+    }
+
+    [[nodiscard]] inline uint32_t GetOverlayEntryCount() const {
       return overlay_entry_count;
     }
 
-    inline uint32_t GetStringPoolIndexOffset() const {
+    [[nodiscard]] inline uint32_t GetStringPoolIndexOffset() const {
       return string_pool_index_offset;
     }
 
@@ -186,6 +204,8 @@
    private:
     uint32_t target_entry_count;
     uint32_t target_entry_inline_count;
+    uint32_t target_entry_inline_value_count;
+    uint32_t config_count;
     uint32_t overlay_entry_count;
     uint32_t string_pool_index_offset;
     Header() = default;
@@ -202,7 +222,7 @@
 
   struct TargetInlineEntry {
     ResourceId target_id;
-    TargetValue value;
+    std::map<ConfigDescription, TargetValue> values;
   };
 
   struct OverlayEntry {
@@ -227,11 +247,11 @@
     return target_inline_entries_;
   }
 
-  const std::vector<OverlayEntry>& GetOverlayEntries() const {
+  [[nodiscard]] const std::vector<OverlayEntry>& GetOverlayEntries() const {
     return overlay_entries_;
   }
 
-  const std::string& GetStringPoolData() const {
+  [[nodiscard]] const std::string& GetStringPoolData() const {
     return string_pool_data_;
   }
 
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index 21862a36..4bad2fa 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -33,7 +33,8 @@
 using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
 
 namespace android::idmap2 {
-using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, TargetValue>>;
+using ConfigMap = std::unordered_map<std::string, TargetValue>;
+using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, ConfigMap>>;
 using OverlayResourceMap = std::map<ResourceId, ResourceId>;
 
 class ResourceMapping {
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 8ec7496..af4dd89 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -46,6 +46,10 @@
 struct TargetValueWithConfig {
   TargetValue value;
   std::string config;
+
+  [[nodiscard]] std::pair<std::string, TargetValue> to_pair() const {
+    return std::make_pair(config, value);
+  }
 };
 
 namespace utils {
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 3bbe9d9..4b271a1 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -70,12 +70,35 @@
   }
 
   static constexpr uint16_t kValueSize = 8U;
+  std::vector<std::pair<ConfigDescription, TargetValue>> target_values;
+  target_values.reserve(data.GetHeader()->GetTargetInlineEntryValueCount());
   for (const auto& target_entry : data.GetTargetInlineEntries()) {
     Write32(target_entry.target_id);
+    Write32(target_values.size());
+    Write32(target_entry.values.size());
+    target_values.insert(
+        target_values.end(), target_entry.values.begin(), target_entry.values.end());
+  }
+
+  std::vector<ConfigDescription> configs;
+  configs.reserve(data.GetHeader()->GetConfigCount());
+  for (const auto& target_entry_value : target_values) {
+    auto config_it = find(configs.begin(), configs.end(), target_entry_value.first);
+    if (config_it != configs.end()) {
+      Write32(config_it - configs.begin());
+    } else {
+      Write32(configs.size());
+      configs.push_back(target_entry_value.first);
+    }
     Write16(kValueSize);
     Write8(0U);  // padding
-    Write8(target_entry.value.data_type);
-    Write32(target_entry.value.data_value);
+    Write8(target_entry_value.second.data_type);
+    Write32(target_entry_value.second.data_value);
+  }
+
+  for( auto& cd : configs) {
+    cd.swapHtoD();
+    stream_.write(reinterpret_cast<char*>(&cd), sizeof(cd));
   }
 
   for (const auto& overlay_entry : data.GetOverlayEntries()) {
@@ -89,6 +112,8 @@
 void BinaryStreamVisitor::visit(const IdmapData::Header& header) {
   Write32(header.GetTargetEntryCount());
   Write32(header.GetTargetInlineEntryCount());
+  Write32(header.GetTargetInlineEntryValueCount());
+  Write32(header.GetConfigCount());
   Write32(header.GetOverlayEntryCount());
   Write32(header.GetStringPoolIndexOffset());
 }
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 06650f6..4efaeea 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -186,6 +186,8 @@
   std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header());
   if (!Read32(stream, &idmap_data_header->target_entry_count) ||
       !Read32(stream, &idmap_data_header->target_entry_inline_count) ||
+      !Read32(stream, &idmap_data_header->target_entry_inline_value_count) ||
+      !Read32(stream, &idmap_data_header->config_count) ||
       !Read32(stream, &idmap_data_header->overlay_entry_count) ||
       !Read32(stream, &idmap_data_header->string_pool_index_offset)) {
     return nullptr;
@@ -207,20 +209,59 @@
     if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &target_entry.overlay_id)) {
       return nullptr;
     }
-    data->target_entries_.push_back(target_entry);
+    data->target_entries_.emplace_back(target_entry);
   }
 
   // Read the mapping of target resource id to inline overlay values.
-  uint8_t unused1;
-  uint16_t unused2;
+  std::vector<std::tuple<TargetInlineEntry, uint32_t, uint32_t>> target_inline_entries;
   for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
     TargetInlineEntry target_entry{};
-    if (!Read32(stream, &target_entry.target_id) || !Read16(stream, &unused2) ||
-        !Read8(stream, &unused1) || !Read8(stream, &target_entry.value.data_type) ||
-        !Read32(stream, &target_entry.value.data_value)) {
+    uint32_t entry_offset;
+    uint32_t entry_count;
+    if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &entry_offset)
+        || !Read32(stream, &entry_count)) {
       return nullptr;
     }
-    data->target_inline_entries_.push_back(target_entry);
+    target_inline_entries.emplace_back(std::make_tuple(target_entry, entry_offset, entry_count));
+  }
+
+  // Read the inline overlay resource values
+  std::vector<std::pair<uint32_t, TargetValue>> target_values;
+  uint8_t unused1;
+  uint16_t unused2;
+  for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
+    uint32_t config_index;
+    if (!Read32(stream, &config_index)) {
+      return nullptr;
+    }
+    TargetValue value;
+    if (!Read16(stream, &unused2)
+        || !Read8(stream, &unused1)
+        || !Read8(stream, &value.data_type)
+        || !Read32(stream, &value.data_value)) {
+      return nullptr;
+    }
+    target_values.emplace_back(std::make_pair(config_index, value));
+  }
+
+  // Read the configurations
+  std::vector<ConfigDescription> configurations;
+  for (size_t i = 0; i < data->header_->GetConfigCount(); i++) {
+    ConfigDescription cd;
+    if (!stream.read(reinterpret_cast<char*>(&cd), sizeof(ConfigDescription))) {
+      return nullptr;
+    }
+    configurations.emplace_back(cd);
+  }
+
+  // Construct complete target inline entries
+  for (auto [target_entry, entry_offset, entry_count] : target_inline_entries) {
+    for(size_t i = 0; i < entry_count; i++) {
+      const auto& target_value = target_values[entry_offset + i];
+      const auto& config = configurations[target_value.first];
+      target_entry.values[config] = target_value.second;
+    }
+    data->target_inline_entries_.emplace_back(target_entry);
   }
 
   // Read the mapping of overlay resource id to target resource id.
@@ -278,12 +319,21 @@
 
   std::unique_ptr<IdmapData> data(new IdmapData());
   data->string_pool_data_ = resource_mapping.GetStringPoolData().to_string();
+  uint32_t inline_value_count = 0;
+  std::set<std::string> config_set;
   for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
     if (auto overlay_resource = std::get_if<ResourceId>(&mapping.second)) {
       data->target_entries_.push_back({mapping.first, *overlay_resource});
     } else {
-      data->target_inline_entries_.push_back(
-          {mapping.first, std::get<TargetValue>(mapping.second)});
+      std::map<ConfigDescription, TargetValue> values;
+      for (const auto& [config, value] : std::get<ConfigMap>(mapping.second)) {
+        config_set.insert(config);
+        ConfigDescription cd;
+        ConfigDescription::Parse(config, &cd);
+        values[cd] = value;
+        inline_value_count++;
+      }
+      data->target_inline_entries_.push_back({mapping.first, values});
     }
   }
 
@@ -295,6 +345,8 @@
   data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size());
   data_header->target_entry_inline_count =
       static_cast<uint32_t>(data->target_inline_entries_.size());
+  data_header->target_entry_inline_value_count = inline_value_count;
+  data_header->config_count = config_set.size();
   data_header->overlay_entry_count = static_cast<uint32_t>(data->overlay_entries_.size());
   data_header->string_pool_index_offset = resource_mapping.GetStringPoolOffset();
   data->header_ = std::move(data_header);
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index d10a278..a44fa75 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -94,14 +94,17 @@
   }
 
   for (auto& target_entry : data.GetTargetInlineEntries()) {
-    stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
-            << utils::DataTypeToString(target_entry.value.data_type);
+    for(auto iter = target_entry.values.begin(); iter != target_entry.values.end(); ++iter) {
+      auto value = iter->second;
+      stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
+              << utils::DataTypeToString(value.data_type);
 
-    if (target_entry.value.data_type == Res_value::TYPE_STRING) {
-      auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset);
-      stream_ << " \"" << str.value_or(StringPiece16(u"")) << "\"";
-    } else {
-      stream_ << " " << base::StringPrintf("0x%08x", target_entry.value.data_value);
+      if (value.data_type == Res_value::TYPE_STRING) {
+        auto str = string_pool.stringAt(value.data_value - string_pool_offset);
+        stream_ << " \"" << str.value_or(StringPiece16(u"")) << "\"";
+      } else {
+        stream_ << " " << base::StringPrintf("0x%08x", value.data_value);
+      }
     }
 
     std::string target_name = kUnknownResourceName;
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 779538c..3531cd7 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -89,22 +89,30 @@
       print(target_entry.target_id, "target id");
     }
 
+
     pad(sizeof(Res_value::size) + sizeof(Res_value::res0));
 
-    print(target_entry.value.data_type, "type: %s",
-          utils::DataTypeToString(target_entry.value.data_type).data());
+    for (auto& target_entry_value : target_entry.values) {
+      auto value = target_entry_value.second;
 
-    Result<std::string> overlay_name(Error(""));
-    if (overlay_ != nullptr &&
-        (target_entry.value.data_value == Res_value::TYPE_REFERENCE ||
-         target_entry.value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
-      overlay_name = overlay_->GetResourceName(target_entry.value.data_value);
-    }
+      print(target_entry_value.first.to_string(), false, "config: %s",
+          target_entry_value.first.toString().string());
 
-    if (overlay_name) {
-      print(target_entry.value.data_value, "data: %s", overlay_name->c_str());
-    } else {
-      print(target_entry.value.data_value, "data");
+      print(value.data_type, "type: %s",
+            utils::DataTypeToString(value.data_type).data());
+
+      Result<std::string> overlay_name(Error(""));
+      if (overlay_ != nullptr &&
+          (value.data_value == Res_value::TYPE_REFERENCE ||
+           value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
+        overlay_name = overlay_->GetResourceName(value.data_value);
+      }
+
+      if (overlay_name) {
+        print(value.data_value, "data: %s", overlay_name->c_str());
+      } else {
+        print(value.data_value, "data");
+      }
     }
   }
 
@@ -138,6 +146,8 @@
 void RawPrintVisitor::visit(const IdmapData::Header& header) {
   print(header.GetTargetEntryCount(), "target entry count");
   print(header.GetTargetInlineEntryCount(), "target inline entry count");
+  print(header.GetTargetInlineEntryValueCount(), "target inline entry value count");
+  print(header.GetConfigCount(), "config count");
   print(header.GetOverlayEntryCount(), "overlay entry count");
   print(header.GetStringPoolIndexOffset(), "string pool index offset");
 }
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 8ebe5aa4..bb31c11 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -161,14 +161,13 @@
 Result<Unit> ResourceMapping::AddMapping(
     ResourceId target_resource,
     const std::variant<OverlayData::ResourceIdValue, TargetValueWithConfig>& value) {
-  if (target_map_.find(target_resource) != target_map_.end()) {
-    return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
-  }
-
   // TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
   // runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
 
   if (auto overlay_resource = std::get_if<OverlayData::ResourceIdValue>(&value)) {
+    if (target_map_.find(target_resource) != target_map_.end()) {
+      return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+    }
     target_map_.insert(std::make_pair(target_resource, overlay_resource->overlay_id));
     if (overlay_resource->rewrite_id) {
       // An overlay resource can override multiple target resources at once. Rewrite the overlay
@@ -176,8 +175,18 @@
       overlay_map_.insert(std::make_pair(overlay_resource->overlay_id, target_resource));
     }
   } else {
-    auto overlay_value = std::get<TargetValueWithConfig>(value);
-    target_map_.insert(std::make_pair(target_resource, overlay_value.value));
+    auto[iter, inserted] = target_map_.try_emplace(target_resource, ConfigMap());
+    auto& resource_value = iter->second;
+    if (!inserted && std::holds_alternative<ResourceId>(resource_value)) {
+      return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+    }
+    auto& config_map = std::get<ConfigMap>(resource_value);
+    const auto& config_value = std::get<TargetValueWithConfig>(value);
+    if (config_map.find(config_value.config) != config_map.end()) {
+      return Error(R"(target resource id "0x%08x" mapped to multiple values with the same config)",
+                   target_resource);
+    }
+    config_map.insert(config_value.to_pair());
   }
 
   return Unit{};
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index bf63327..f1eeab9 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -84,8 +84,10 @@
   const auto& target_inline_entries2 = data2->GetTargetInlineEntries();
   ASSERT_EQ(target_inline_entries1.size(), target_inline_entries2.size());
   ASSERT_EQ(target_inline_entries1[0].target_id, target_inline_entries2[0].target_id);
-  ASSERT_EQ(target_inline_entries1[0].value.data_type, target_inline_entries2[0].value.data_type);
-  ASSERT_EQ(target_inline_entries1[0].value.data_value, target_inline_entries2[0].value.data_value);
+  ASSERT_EQ(target_inline_entries1[0].values.begin()->second.data_type,
+      target_inline_entries2[0].values.begin()->second.data_type);
+  ASSERT_EQ(target_inline_entries1[0].values.begin()->second.data_value,
+      target_inline_entries2[0].values.begin()->second.data_value);
 
   const auto& overlay_entries1 = data1->GetOverlayEntries();
   const auto& overlay_entries2 = data2->GetOverlayEntries();
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index ee9a424..7b7dc17 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -47,10 +47,11 @@
   ASSERT_EQ((entry).target_id, (target_resid));                 \
   ASSERT_EQ((entry).overlay_id, (overlay_resid))
 
-#define ASSERT_TARGET_INLINE_ENTRY(entry, target_resid, expected_type, expected_value) \
-  ASSERT_EQ((entry).target_id, target_resid);                                          \
-  ASSERT_EQ((entry).value.data_type, (expected_type));                                 \
-  ASSERT_EQ((entry).value.data_value, (expected_value))
+#define ASSERT_TARGET_INLINE_ENTRY(entry, target_resid, ex_config, expected_type, expected_value) \
+  ASSERT_EQ((entry).target_id, target_resid);                                                     \
+  ASSERT_EQ((entry).values.begin()->first.to_string(), (ex_config));                              \
+  ASSERT_EQ((entry).values.begin()->second.data_type, (expected_type));                           \
+  ASSERT_EQ((entry).values.begin()->second.data_value, (expected_value))
 
 #define ASSERT_OVERLAY_ENTRY(entry, overlay_resid, target_resid) \
   ASSERT_EQ((entry).overlay_id, (overlay_resid));                \
@@ -67,7 +68,7 @@
   std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
   ASSERT_THAT(header, NotNull());
   ASSERT_EQ(header->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(header->GetVersion(), 0x08U);
+  ASSERT_EQ(header->GetVersion(), 0x09U);
   ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
   ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
   ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
@@ -122,8 +123,8 @@
 
   const auto& target_inline_entries = data->GetTargetInlineEntries();
   ASSERT_EQ(target_inline_entries.size(), 1U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, Res_value::TYPE_INT_HEX,
-                             0x12345678);
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000,  "land-xxhdpi-v7",
+                             Res_value::TYPE_INT_HEX, 0x12345678);
 
   const auto& overlay_entries = data->GetOverlayEntries();
   ASSERT_EQ(target_entries.size(), 3U);
@@ -142,7 +143,7 @@
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
+  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
   ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
   ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies);
@@ -165,8 +166,8 @@
 
   const auto& target_inline_entries = data->GetTargetInlineEntries();
   ASSERT_EQ(target_inline_entries.size(), 1U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, Res_value::TYPE_INT_HEX,
-                             0x12345678);
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000,  "land-xxhdpi-v7",
+                             Res_value::TYPE_INT_HEX, 0x12345678);
 
   const auto& overlay_entries = data->GetOverlayEntries();
   ASSERT_EQ(target_entries.size(), 3U);
@@ -203,7 +204,7 @@
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
-  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
+  ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
   ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
   ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
@@ -261,9 +262,9 @@
 
   auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
                   .SetOverlayable("TestResources")
-                  .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "")
-                  .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "")
-                  .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "")
+                  .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7")
+                  .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land")
+                  .SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7")
                   .Build();
 
   ASSERT_TRUE(frro);
@@ -295,11 +296,11 @@
 
   const auto& target_inline_entries = data->GetTargetInlineEntries();
   ASSERT_EQ(target_inline_entries.size(), 3U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1, "land-xxhdpi-v7",
                              Res_value::TYPE_INT_DEC, 2U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1, "land",
                              Res_value::TYPE_REFERENCE, 0x7f010000);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str2,
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str2, "xxhdpi-v7",
                              Res_value::TYPE_STRING,
                              (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1));
 }
@@ -442,9 +443,9 @@
   constexpr size_t overlay_string_pool_size = 10U;
   const auto& target_inline_entries = data->GetTargetInlineEntries();
   ASSERT_EQ(target_inline_entries.size(), 2U);
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1, std::string(),
                              Res_value::TYPE_INT_DEC, 73U);  // -> 73
-  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
+  ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1, std::string(),
                              Res_value::TYPE_STRING,
                              overlay_string_pool_size + 0U);  // -> "Hello World"
 
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index a6371cb..7112eeb 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -64,7 +64,7 @@
   (*idmap)->accept(&visitor);
 
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "00000008  version\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000009  version\n", stream.str());
   ASSERT_CONTAINS_REGEX(
       StringPrintf(ADDRESS "%s  target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
       stream.str());
@@ -75,6 +75,8 @@
   ASSERT_CONTAINS_REGEX(ADDRESS "00000001  enforce overlayable\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  target entry count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000000  target inline entry count", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000000  target inline entry value count", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000000  config count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  overlay entry count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "0000000a  string pool index offset", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f010000  target id: integer/int1", stream.str());
@@ -111,7 +113,7 @@
   (*idmap)->accept(&visitor);
 
   ASSERT_CONTAINS_REGEX(ADDRESS "504d4449  magic\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "00000008  version\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000009  version\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00001234  target crc\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00005678  overlay crc\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000011  fulfilled policies: public|signature\n", stream.str());
@@ -124,17 +126,25 @@
   ASSERT_CONTAINS_REGEX(ADDRESS "........  overlay name: OverlayName\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000003  target entry count\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000001  target inline entry count\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000001  target inline entry value count", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "00000001  config count", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000003  overlay entry count\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000000  string pool index offset\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  target id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  overlay id\n", stream.str());
-  ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  target id\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030000  target id\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030000  overlay id\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030002  target id\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f030001  overlay id\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "7f040000  target id\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "0000000e  config: land-xxhdpi-v7 size\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "........  config: land-xxhdpi-v7\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "      11  type: integer\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "12345678  data\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f020000  overlay id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "7f030002  target id\n", stream.str());
   ASSERT_CONTAINS_REGEX(ADDRESS "00000004  string pool size\n", stream.str());
-  ASSERT_CONTAINS_REGEX("000000a4: ........  string pool\n", stream.str());
+  ASSERT_CONTAINS_REGEX(ADDRESS "........  string pool\n", stream.str());
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index ca9a444..016d427 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -111,19 +111,20 @@
     return Error("Failed to find mapping for target resource");
   }
 
-  auto actual_overlay_value = std::get_if<TargetValue>(&entry_map->second);
-  if (actual_overlay_value == nullptr) {
+  auto config_map = std::get_if<ConfigMap>(&entry_map->second);
+  if (config_map == nullptr || config_map->empty()) {
     return Error("Target resource is not mapped to an inline value");
   }
+  auto actual_overlay_value = config_map->begin()->second;
 
-  if (actual_overlay_value->data_type != type) {
+  if (actual_overlay_value.data_type != type) {
     return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
-                 actual_overlay_value->data_type);
+                 actual_overlay_value.data_type);
   }
 
-  if (actual_overlay_value->data_value != value) {
+  if (actual_overlay_value.data_value != value) {
     return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
-                 actual_overlay_value->data_value);
+                 actual_overlay_value.data_value);
   }
 
   return Result<Unit>({});
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index 6b5f3a8..45740e2 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -30,7 +30,7 @@
     0x49, 0x44, 0x4d, 0x50,
 
     // 0x4: version
-    0x08, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00,
 
     // 0x8: target crc
     0x34, 0x12, 0x00, 0x00,
@@ -76,66 +76,123 @@
     // 0x58: target_inline_entry_count
     0x01, 0x00, 0x00, 0x00,
 
-    // 0x5c: overlay_entry_count
+    // 0x5c: target_inline_entry_value_count
+    0x01, 0x00, 0x00, 0x00,
+
+    // 0x60: config_count
+    0x01, 0x00, 0x00, 0x00,
+
+    // 0x64: overlay_entry_count
     0x03, 0x00, 0x00, 0x00,
 
-    // 0x60: string_pool_offset
+    // 0x68: string_pool_offset
     0x00, 0x00, 0x00, 0x00,
 
     // TARGET ENTRIES
-    // 0x64: target id (0x7f020000)
+    // 0x6c: target id (0x7f020000)
     0x00, 0x00, 0x02, 0x7f,
 
-    // 0x68: overlay_id (0x7f020000)
+    // 0x70: overlay_id (0x7f020000)
     0x00, 0x00, 0x02, 0x7f,
 
-    // 0x6c: target id (0x7f030000)
+    // 0x74: target id (0x7f030000)
     0x00, 0x00, 0x03, 0x7f,
 
-    // 0x70: overlay_id (0x7f030000)
+    // 0x78: overlay_id (0x7f030000)
     0x00, 0x00, 0x03, 0x7f,
 
-    // 0x74: target id (0x7f030002)
+    // 0x7c: target id (0x7f030002)
     0x02, 0x00, 0x03, 0x7f,
 
-    // 0x78: overlay_id (0x7f030001)
+    // 0x80: overlay_id (0x7f030001)
     0x01, 0x00, 0x03, 0x7f,
 
     // INLINE TARGET ENTRIES
 
-    // 0x7c: target_id
+    // 0x84: target_id
     0x00, 0x00, 0x04, 0x7f,
 
-    // 0x80: Res_value::size (value ignored by idmap)
+    // 0x88: start value index
+    0x00, 0x00, 0x00, 0x00,
+
+    // 0x8c: value count
+    0x01, 0x00, 0x00, 0x00,
+
+    // INLINE TARGET ENTRY VALUES
+
+    // 0x90: config index
+    0x00, 0x00, 0x00, 0x00,
+
+    // 0x94: Res_value::size (value ignored by idmap)
     0x08, 0x00,
 
-    // 0x82: Res_value::res0 (value ignored by idmap)
+    // 0x98: Res_value::res0 (value ignored by idmap)
     0x00,
 
-    // 0x83: Res_value::dataType (TYPE_INT_HEX)
+    // 0x9c: Res_value::dataType (TYPE_INT_HEX)
     0x11,
 
-    // 0x84: Res_value::data
+    // 0xa0: Res_value::data
     0x78, 0x56, 0x34, 0x12,
 
+    // CONFIGURATIONS
+
+    // 0xa4: ConfigDescription
+    // size
+    0x40, 0x00, 0x00, 0x00,
+    // 0xa8: imsi
+    0x00, 0x00, 0x00, 0x00,
+    // 0xac: locale
+    0x00, 0x00, 0x00, 0x00,
+    // 0xb0: screenType
+    0x02, 0x00, 0xe0, 0x01,
+    // 0xb4: input
+    0x00, 0x00, 0x00, 0x00,
+    // 0xb8: screenSize
+    0x00, 0x00, 0x00, 0x00,
+    // 0xbc: version
+    0x07, 0x00, 0x00, 0x00,
+    // 0xc0: screenConfig
+    0x00, 0x00, 0x00, 0x00,
+    // 0xc4: screenSizeDp
+    0x00, 0x00, 0x00, 0x00,
+    // 0xc8: localeScript
+    0x00, 0x00, 0x00, 0x00,
+    // 0xcc: localVariant(1)
+    0x00, 0x00, 0x00, 0x00,
+    // 0xd0: localVariant(2)
+    0x00, 0x00, 0x00, 0x00,
+    // 0xd4: screenConfig2
+    0x00, 0x00, 0x00, 0x00,
+    // 0xd8: localeScriptWasComputed
+    0x00,
+    // 0xd9: localeNumberingSystem(1)
+    0x00, 0x00, 0x00, 0x00,
+    // 0xdd: localeNumberingSystem(2)
+    0x00, 0x00, 0x00, 0x00,
+
+    // 0xe1: padding
+    0x00, 0x00, 0x00,
+
+
     // OVERLAY ENTRIES
-    // 0x88: 0x7f020000 -> 0x7f020000
+    // 0xe4: 0x7f020000 -> 0x7f020000
     0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
 
-    // 0x90: 0x7f030000 -> 0x7f030000
+    // 0xec: 0x7f030000 -> 0x7f030000
     0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
 
-    // 0x98: 0x7f030001 -> 0x7f030002
+    // 0xf4: 0x7f030001 -> 0x7f030002
     0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
 
-    // 0xa0: string pool
+    // 0xfc: string pool
     // string length,
     0x04, 0x00, 0x00, 0x00,
 
-    // 0xa4 string contents "test"
+    // 0x100 string contents "test"
     0x74, 0x65, 0x73, 0x74};
 
-const unsigned int kIdmapRawDataLen = 0xa8;
+const unsigned int kIdmapRawDataLen = 0x104;
 const unsigned int kIdmapRawDataOffset = 0x54;
 const unsigned int kIdmapRawDataTargetCrc = 0x1234;
 const unsigned int kIdmapRawOverlayCrc = 0x5678;
diff --git a/core/api/current.txt b/core/api/current.txt
index 0b41068..1bf0d0e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -636,6 +636,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enableOnBackInvokedCallback = 16844396; // 0x101066c
+    field public static final int enableTextStylingShortcuts;
     field public static final int enableVrMode = 16844069; // 0x1010525
     field public static final int enabled = 16842766; // 0x101000e
     field public static final int end = 16843996; // 0x10104dc
@@ -2113,6 +2114,7 @@
     field public static final int addToDictionary = 16908330; // 0x102002a
     field public static final int autofill = 16908355; // 0x1020043
     field public static final int background = 16908288; // 0x1020000
+    field public static final int bold;
     field public static final int button1 = 16908313; // 0x1020019
     field public static final int button2 = 16908314; // 0x102001a
     field public static final int button3 = 16908315; // 0x102001b
@@ -2138,6 +2140,7 @@
     field public static final int inputExtractAccessories = 16908378; // 0x102005a
     field public static final int inputExtractAction = 16908377; // 0x1020059
     field public static final int inputExtractEditText = 16908325; // 0x1020025
+    field public static final int italic;
     field @Deprecated public static final int keyboardView = 16908326; // 0x1020026
     field public static final int list = 16908298; // 0x102000a
     field public static final int list_container = 16908351; // 0x102003f
@@ -2169,6 +2172,7 @@
     field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int underline;
     field public static final int undo = 16908338; // 0x1020032
     field public static final int widget_frame = 16908312; // 0x1020018
   }
@@ -15124,7 +15128,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.graphics.ParcelableColorSpace> CREATOR;
   }
 
-  public class Path implements java.lang.Iterable<android.graphics.PathIterator.Segment> {
+  public class Path {
     ctor public Path();
     ctor public Path(@Nullable android.graphics.Path);
     method public void addArc(@NonNull android.graphics.RectF, float, float);
@@ -15151,6 +15155,7 @@
     method public void cubicTo(float, float, float, float, float, float);
     method @NonNull public android.graphics.Path.FillType getFillType();
     method public int getGenerationId();
+    method @NonNull public android.graphics.PathIterator getPathIterator();
     method public void incReserve(int);
     method public boolean interpolate(@NonNull android.graphics.Path, float, @NonNull android.graphics.Path);
     method @Deprecated public boolean isConvex();
@@ -15158,7 +15163,6 @@
     method public boolean isInterpolatable(@NonNull android.graphics.Path);
     method public boolean isInverseFillType();
     method public boolean isRect(@Nullable android.graphics.RectF);
-    method @NonNull public android.graphics.PathIterator iterator();
     method public void lineTo(float, float);
     method public void moveTo(float, float);
     method public void offset(float, float, @Nullable android.graphics.Path);
@@ -16892,6 +16896,7 @@
     field public static final int DATASPACE_DEPTH = 4096; // 0x1000
     field public static final int DATASPACE_DISPLAY_P3 = 143261696; // 0x88a0000
     field public static final int DATASPACE_DYNAMIC_DEPTH = 4098; // 0x1002
+    field public static final int DATASPACE_HEIF = 4100; // 0x1004
     field public static final int DATASPACE_JFIF = 146931712; // 0x8c20000
     field public static final int DATASPACE_SCRGB = 411107328; // 0x18810000
     field public static final int DATASPACE_SCRGB_LINEAR = 406913024; // 0x18410000
@@ -48662,6 +48667,9 @@
     field public static final int KEYCODE_K = 39; // 0x27
     field public static final int KEYCODE_KANA = 218; // 0xda
     field public static final int KEYCODE_KATAKANA_HIRAGANA = 215; // 0xd7
+    field public static final int KEYCODE_KEYBOARD_BACKLIGHT_DOWN = 305; // 0x131
+    field public static final int KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307; // 0x133
+    field public static final int KEYCODE_KEYBOARD_BACKLIGHT_UP = 306; // 0x132
     field public static final int KEYCODE_L = 40; // 0x28
     field public static final int KEYCODE_LANGUAGE_SWITCH = 204; // 0xcc
     field public static final int KEYCODE_LAST_CHANNEL = 229; // 0xe5
@@ -48763,6 +48771,10 @@
     field public static final int KEYCODE_STEM_2 = 266; // 0x10a
     field public static final int KEYCODE_STEM_3 = 267; // 0x10b
     field public static final int KEYCODE_STEM_PRIMARY = 264; // 0x108
+    field public static final int KEYCODE_STYLUS_BUTTON_PRIMARY = 308; // 0x134
+    field public static final int KEYCODE_STYLUS_BUTTON_SECONDARY = 309; // 0x135
+    field public static final int KEYCODE_STYLUS_BUTTON_TAIL = 311; // 0x137
+    field public static final int KEYCODE_STYLUS_BUTTON_TERTIARY = 310; // 0x136
     field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
     field public static final int KEYCODE_SYM = 63; // 0x3f
     field public static final int KEYCODE_SYSRQ = 120; // 0x78
@@ -51841,6 +51853,7 @@
     field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
     field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
     field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
+    field public static final int CONTENT_CHANGE_TYPE_INVALID = 1024; // 0x400
     field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
     field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
     field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
@@ -52942,7 +52955,7 @@
 package android.view.inputmethod {
 
   public class BaseInputConnection implements android.view.inputmethod.InputConnection {
-    ctor public BaseInputConnection(android.view.View, boolean);
+    ctor public BaseInputConnection(@NonNull android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
     method @CallSuper public void closeConnection();
@@ -52954,24 +52967,24 @@
     method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
-    method public static int getComposingSpanEnd(android.text.Spannable);
-    method public static int getComposingSpanStart(android.text.Spannable);
+    method public static int getComposingSpanEnd(@NonNull android.text.Spannable);
+    method public static int getComposingSpanStart(@NonNull android.text.Spannable);
     method public int getCursorCapsMode(int);
-    method public android.text.Editable getEditable();
-    method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
-    method public android.os.Handler getHandler();
-    method public CharSequence getSelectedText(int);
+    method @Nullable public android.text.Editable getEditable();
+    method @Nullable public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+    method @Nullable public android.os.Handler getHandler();
+    method @Nullable public CharSequence getSelectedText(int);
     method @Nullable public CharSequence getTextAfterCursor(@IntRange(from=0) int, int);
     method @Nullable public CharSequence getTextBeforeCursor(@IntRange(from=0) int, int);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(String, android.os.Bundle);
-    method public static final void removeComposingSpans(android.text.Spannable);
+    method public static final void removeComposingSpans(@NonNull android.text.Spannable);
     method public boolean reportFullscreenMode(boolean);
     method public boolean requestCursorUpdates(int);
     method public boolean sendKeyEvent(android.view.KeyEvent);
     method public boolean setComposingRegion(int, int);
-    method public static void setComposingSpans(android.text.Spannable);
+    method public static void setComposingSpans(@NonNull android.text.Spannable);
     method public boolean setComposingText(CharSequence, int);
     method public boolean setSelection(int, int);
   }
@@ -53052,6 +53065,24 @@
     method @NonNull public android.view.inputmethod.DeleteGesture.Builder setGranularity(int);
   }
 
+  public final class DeleteRangeGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.RectF getDeletionEndArea();
+    method @NonNull public android.graphics.RectF getDeletionStartArea();
+    method public int getGranularity();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.DeleteRangeGesture> CREATOR;
+  }
+
+  public static final class DeleteRangeGesture.Builder {
+    ctor public DeleteRangeGesture.Builder();
+    method @NonNull public android.view.inputmethod.DeleteRangeGesture build();
+    method @NonNull public android.view.inputmethod.DeleteRangeGesture.Builder setDeletionEndArea(@NonNull android.graphics.RectF);
+    method @NonNull public android.view.inputmethod.DeleteRangeGesture.Builder setDeletionStartArea(@NonNull android.graphics.RectF);
+    method @NonNull public android.view.inputmethod.DeleteRangeGesture.Builder setFallbackText(@Nullable String);
+    method @NonNull public android.view.inputmethod.DeleteRangeGesture.Builder setGranularity(int);
+  }
+
   public final class EditorBoundsInfo implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.graphics.RectF getEditorBounds();
@@ -53151,9 +53182,13 @@
   public abstract class HandwritingGesture {
     method @Nullable public String getFallbackText();
     field public static final int GESTURE_TYPE_DELETE = 4; // 0x4
+    field public static final int GESTURE_TYPE_DELETE_RANGE = 64; // 0x40
     field public static final int GESTURE_TYPE_INSERT = 2; // 0x2
+    field public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 16; // 0x10
     field public static final int GESTURE_TYPE_NONE = 0; // 0x0
+    field public static final int GESTURE_TYPE_REMOVE_SPACE = 8; // 0x8
     field public static final int GESTURE_TYPE_SELECT = 1; // 0x1
+    field public static final int GESTURE_TYPE_SELECT_RANGE = 32; // 0x20
     field public static final int GRANULARITY_CHARACTER = 2; // 0x2
     field public static final int GRANULARITY_WORD = 1; // 0x1
   }
@@ -53493,6 +53528,35 @@
     method @NonNull public android.view.inputmethod.InsertGesture.Builder setTextToInsert(@NonNull String);
   }
 
+  public final class JoinOrSplitGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.PointF getJoinOrSplitPoint();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.JoinOrSplitGesture> CREATOR;
+  }
+
+  public static final class JoinOrSplitGesture.Builder {
+    ctor public JoinOrSplitGesture.Builder();
+    method @NonNull public android.view.inputmethod.JoinOrSplitGesture build();
+    method @NonNull public android.view.inputmethod.JoinOrSplitGesture.Builder setFallbackText(@Nullable String);
+    method @NonNull public android.view.inputmethod.JoinOrSplitGesture.Builder setJoinOrSplitPoint(@NonNull android.graphics.PointF);
+  }
+
+  public final class RemoveSpaceGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.PointF getEndPoint();
+    method @NonNull public android.graphics.PointF getStartPoint();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.RemoveSpaceGesture> CREATOR;
+  }
+
+  public static final class RemoveSpaceGesture.Builder {
+    ctor public RemoveSpaceGesture.Builder();
+    method @NonNull public android.view.inputmethod.RemoveSpaceGesture build();
+    method @NonNull public android.view.inputmethod.RemoveSpaceGesture.Builder setFallbackText(@Nullable String);
+    method @NonNull public android.view.inputmethod.RemoveSpaceGesture.Builder setPoints(@NonNull android.graphics.PointF, @NonNull android.graphics.PointF);
+  }
+
   public final class SelectGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
     method public int describeContents();
     method public int getGranularity();
@@ -53509,6 +53573,24 @@
     method @NonNull public android.view.inputmethod.SelectGesture.Builder setSelectionArea(@NonNull android.graphics.RectF);
   }
 
+  public final class SelectRangeGesture extends android.view.inputmethod.HandwritingGesture implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getGranularity();
+    method @NonNull public android.graphics.RectF getSelectionEndArea();
+    method @NonNull public android.graphics.RectF getSelectionStartArea();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.SelectRangeGesture> CREATOR;
+  }
+
+  public static final class SelectRangeGesture.Builder {
+    ctor public SelectRangeGesture.Builder();
+    method @NonNull public android.view.inputmethod.SelectRangeGesture build();
+    method @NonNull public android.view.inputmethod.SelectRangeGesture.Builder setFallbackText(@Nullable String);
+    method @NonNull public android.view.inputmethod.SelectRangeGesture.Builder setGranularity(int);
+    method @NonNull public android.view.inputmethod.SelectRangeGesture.Builder setSelectionEndArea(@NonNull android.graphics.RectF);
+    method @NonNull public android.view.inputmethod.SelectRangeGesture.Builder setSelectionStartArea(@NonNull android.graphics.RectF);
+  }
+
   public final class SurroundingText implements android.os.Parcelable {
     ctor public SurroundingText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0xffffffff) int);
     method public int describeContents();
@@ -55992,9 +56074,11 @@
     ctor public EditText(android.content.Context, android.util.AttributeSet, int, int);
     method public void extendSelection(int);
     method public android.text.Editable getText();
+    method public boolean isStyleShortcutEnabled();
     method public void selectAll();
     method public void setSelection(int, int);
     method public void setSelection(int);
+    method public void setStyleShortcutsEnabled(boolean);
   }
 
   public interface ExpandableListAdapter {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f09244a..449900d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1318,6 +1318,7 @@
     method @NonNull public java.time.Instant getStartTime();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEvent> CREATOR;
+    field public static final int EVENT_BACK_DOUBLE_TAP = 3; // 0x3
     field public static final int EVENT_COUGH = 1; // 0x1
     field public static final int EVENT_SNORE = 2; // 0x2
     field public static final int EVENT_UNKNOWN = 0; // 0x0
@@ -6665,6 +6666,15 @@
 
 }
 
+package android.media.projection {
+
+  public class MediaProjectionGlobal {
+    method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface);
+    method @NonNull public static android.media.projection.MediaProjectionGlobal getInstance();
+  }
+
+}
+
 package android.media.session {
 
   public final class MediaSessionManager {
@@ -10347,6 +10357,7 @@
     field public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
     field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
     field public static final String NAMESPACE_AUTOFILL = "autofill";
+    field public static final String NAMESPACE_BACKUP_AND_RESTORE = "backup_and_restore";
     field public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
     field public static final String NAMESPACE_BIOMETRICS = "biometrics";
     field public static final String NAMESPACE_BLOBSTORE = "blobstore";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 96b8141..085bd55 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -523,8 +523,8 @@
     method @NonNull public static String operationToString(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
     method @RequiresPermission(allOf={android.Manifest.permission.MANAGE_DEVICE_ADMINS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwner(@NonNull android.content.ComponentName, @Nullable String, int);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwner(@NonNull android.content.ComponentName, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, int);
     method public void setDeviceOwnerType(@NonNull android.content.ComponentName, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void setNextOperationSafety(int, int);
     method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName, boolean);
@@ -2160,10 +2160,15 @@
     field public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
     field public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
     field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
+    field public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager";
     field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
     field public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
   }
 
+  public interface InputMethodManagerDeviceConfig {
+    field public static final String KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS = "hide_ime_when_no_editor_focus";
+  }
+
   public final class Settings {
     field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
   }
@@ -2704,7 +2709,7 @@
 
   public class SparseArrayMap<K, V> {
     ctor public SparseArrayMap();
-    method public void add(int, @NonNull K, @Nullable V);
+    method public V add(int, @NonNull K, @Nullable V);
     method public void clear();
     method public boolean contains(int, @NonNull K);
     method public void delete(int);
@@ -2849,7 +2854,7 @@
     method public static String actionToString(int);
     method public final void setDisplayId(int);
     field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
-    field public static final int LAST_KEYCODE = 304; // 0x130
+    field public static final int LAST_KEYCODE = 311; // 0x137
   }
 
   public final class KeyboardShortcutGroup implements android.os.Parcelable {
@@ -3343,20 +3348,59 @@
     ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor);
     method @NonNull public java.util.concurrent.Executor getExecutor();
     method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken();
-    method public void onActivityReparentedToTask(@NonNull android.window.WindowContainerTransaction, int, @NonNull android.content.Intent, @NonNull android.os.IBinder);
-    method public void onTaskFragmentAppeared(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
-    method public void onTaskFragmentError(@NonNull android.window.WindowContainerTransaction, @NonNull android.os.IBinder, @Nullable android.window.TaskFragmentInfo, int, @NonNull Throwable);
-    method public void onTaskFragmentInfoChanged(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
-    method public void onTaskFragmentParentInfoChanged(@NonNull android.window.WindowContainerTransaction, int, @NonNull android.content.res.Configuration);
-    method public void onTaskFragmentVanished(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.TaskFragmentInfo);
+    method public void onTransactionReady(@NonNull android.window.TaskFragmentTransaction);
     method @CallSuper public void registerOrganizer();
     method @CallSuper public void unregisterOrganizer();
+    field public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
+    field public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info";
+    field public static final String KEY_ERROR_CALLBACK_THROWABLE = "fragment_throwable";
   }
 
   public final class TaskFragmentOrganizerToken implements android.os.Parcelable {
     field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentOrganizerToken> CREATOR;
   }
 
+  public final class TaskFragmentTransaction implements android.os.Parcelable {
+    ctor public TaskFragmentTransaction();
+    method public void addChange(@Nullable android.window.TaskFragmentTransaction.Change);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.window.TaskFragmentTransaction.Change> getChanges();
+    method @NonNull public android.os.IBinder getTransactionToken();
+    method public boolean isEmpty();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentTransaction> CREATOR;
+    field public static final int TYPE_ACTIVITY_REPARENTED_TO_TASK = 6; // 0x6
+    field public static final int TYPE_TASK_FRAGMENT_APPEARED = 1; // 0x1
+    field public static final int TYPE_TASK_FRAGMENT_ERROR = 5; // 0x5
+    field public static final int TYPE_TASK_FRAGMENT_INFO_CHANGED = 2; // 0x2
+    field public static final int TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED = 4; // 0x4
+    field public static final int TYPE_TASK_FRAGMENT_VANISHED = 3; // 0x3
+  }
+
+  public static final class TaskFragmentTransaction.Change implements android.os.Parcelable {
+    ctor public TaskFragmentTransaction.Change(int);
+    method public int describeContents();
+    method @Nullable public android.content.Intent getActivityIntent();
+    method @Nullable public android.os.IBinder getActivityToken();
+    method @NonNull public android.os.Bundle getErrorBundle();
+    method @Nullable public android.os.IBinder getErrorCallbackToken();
+    method @Nullable public android.content.res.Configuration getTaskConfiguration();
+    method @Nullable public android.window.TaskFragmentInfo getTaskFragmentInfo();
+    method @Nullable public android.os.IBinder getTaskFragmentToken();
+    method public int getTaskId();
+    method public int getType();
+    method @NonNull public android.window.TaskFragmentTransaction.Change setActivityIntent(@NonNull android.content.Intent);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setActivityToken(@NonNull android.os.IBinder);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setErrorBundle(@NonNull android.os.Bundle);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setErrorCallbackToken(@Nullable android.os.IBinder);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setTaskConfiguration(@NonNull android.content.res.Configuration);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setTaskFragmentInfo(@NonNull android.window.TaskFragmentInfo);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setTaskFragmentToken(@NonNull android.os.IBinder);
+    method @NonNull public android.window.TaskFragmentTransaction.Change setTaskId(int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskFragmentTransaction.Change> CREATOR;
+  }
+
   public class TaskOrganizer extends android.window.WindowOrganizer {
     ctor public TaskOrganizer();
     method @BinderThread public void copySplashScreenView(int);
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index 1585f99..93888ef 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -517,7 +517,8 @@
         @Override
         public void invalidateInput(EditorInfo editorInfo,
                 IRemoteAccessibilityInputConnection connection, int sessionId) {
-            if (!mStartedInputConnection.isSameConnection(connection)) {
+            if (!mEnabled || mStartedInputConnection == null
+                    || !mStartedInputConnection.isSameConnection(connection)) {
                 // This is not an error, and can be safely ignored.
                 return;
             }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d899dab..dfef279 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4216,13 +4216,23 @@
         }
     }*/
 
+    /** @hide
+     * Determines whether the given UID can access unexported components
+     * @param uid the calling UID
+     * @return true if the calling UID is ROOT or SYSTEM
+     */
+    public static boolean canAccessUnexportedComponents(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        return (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID);
+    }
+
     /** @hide */
     @UnsupportedAppUsage
     public static int checkComponentPermission(String permission, int uid,
             int owningUid, boolean exported) {
         // Root, system server get to do everything.
         final int appId = UserHandle.getAppId(uid);
-        if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
+        if (canAccessUnexportedComponents(uid)) {
             return PackageManager.PERMISSION_GRANTED;
         }
         // Isolated processes don't get any permissions.
@@ -4350,20 +4360,28 @@
     }
 
     /**
-     * Starts the given user in background and associate the user with the given display.
+     * Starts the given user in background and assign the user to the given display.
      *
      * <p>This method will allow the user to launch activities on that display, and it's typically
      * used only on automotive builds when the vehicle has multiple displays (you can verify if it's
-     * supported by calling {@link UserManager#isBackgroundUsersOnSecondaryDisplaysSupported()}).
+     * supported by calling {@link UserManager#isUsersOnSecondaryDisplaysSupported()}).
      *
-     * @return whether the user was started.
+     * <p><b>NOTE:</b> differently from {@link #switchUser(int)}, which stops the current foreground
+     * user before starting a new one, this method does not stop the previous user running in
+     * background in the display, and it will return {@code false} in this case. It's up to the
+     * caller to call {@link #stopUser(int, boolean)} before starting a new user.
+     *
+     * @param userId user to be started in the display. It will return {@code false} if the user is
+     * a profile, the {@link #getCurrentUser()}, the {@link UserHandle#SYSTEM system user}, or
+     * does not exist.
+     *
+     * @param displayId id of the display, it must exist.
+     *
+     * @return whether the operation succeeded. Notice that if the user was already started in such
+     * display before, it will return {@code false}.
      *
      * @throws UnsupportedOperationException if the device does not support background users on
      * secondary displays.
-     * @throws IllegalArgumentException if the display does not exist.
-     * @throws IllegalStateException if the user cannot be started on that display (for example, if
-     * there's already a user using that display or if the user is already associated with other
-     * display).
      *
      * @hide
      */
@@ -4372,6 +4390,10 @@
             android.Manifest.permission.CREATE_USERS})
     public boolean startUserInBackgroundOnSecondaryDisplay(@UserIdInt int userId,
             int displayId) {
+        if (!UserManager.isUsersOnSecondaryDisplaysEnabled()) {
+            throw new UnsupportedOperationException(
+                    "device does not support users on secondary displays");
+        }
         try {
             return getService().startUserInBackgroundOnSecondaryDisplay(userId, displayId);
         } catch (RemoteException e) {
@@ -4532,6 +4554,10 @@
     /**
      * Stops the given {@code userId}.
      *
+     * <p><b>NOTE:</b> on systems that support
+     * {@link UserManager#isUsersOnSecondaryDisplaysSupported() background users on secondary
+     * displays}, this method will also unassign the user from the display it was started on.
+     *
      * @hide
      */
     @TestApi
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 82eb62d..cf5f10b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1176,9 +1176,16 @@
             data.mSerializedSystemFontMap = serializedSystemFontMap;
             data.startRequestedElapsedTime = startRequestedElapsedTime;
             data.startRequestedUptime = startRequestedUptime;
+            updateCompatOverrideScale(compatInfo);
+            CompatibilityInfo.applyOverrideScaleIfNeeded(config);
             sendMessage(H.BIND_APPLICATION, data);
         }
 
+        private void updateCompatOverrideScale(CompatibilityInfo info) {
+            CompatibilityInfo.setOverrideInvertedScale(
+                    info.hasOverrideScaling() ? info.applicationInvertedScale : 1f);
+        }
+
         public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = entryPoint;
@@ -1755,6 +1762,7 @@
             UpdateCompatibilityData ucd = new UpdateCompatibilityData();
             ucd.pkg = pkg;
             ucd.info = info;
+            updateCompatOverrideScale(info);
             sendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
         }
 
@@ -7830,7 +7838,7 @@
                         Files.move(new File(oldPath).toPath(), new File(newPath).toPath(),
                                 StandardCopyOption.REPLACE_EXISTING);
                     } catch (IOException e2) {
-                        Log.e(TAG, "Rename recovery failed ", e);
+                        Log.e(TAG, "Rename recovery failed ", e2);
                         throw e;
                     }
                 } else {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 877e7d3..6f4bb45 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -145,7 +145,10 @@
      * that it is preserved through activty destroy and restore.
      */
     private ArrayList<String> getPendingExitNames() {
-        if (mPendingExitNames == null && mEnterTransitionCoordinator != null) {
+        if (mPendingExitNames == null
+                && mEnterTransitionCoordinator != null
+                && !mEnterTransitionCoordinator.isReturning()
+        ) {
             mPendingExitNames = mEnterTransitionCoordinator.getPendingExitSharedElementNames();
         }
         return mPendingExitNames;
@@ -202,6 +205,7 @@
             restoreExitedViews();
             activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
         }
+        getPendingExitNames(); // Set mPendingExitNames before resetting mEnterTransitionCoordinator
         mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
                 resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning(),
                 mEnterActivityOptions.isCrossTask());
@@ -250,6 +254,7 @@
     public void onStop(Activity activity) {
         restoreExitedViews();
         if (mEnterTransitionCoordinator != null) {
+            getPendingExitNames(); // Set mPendingExitNames before clearing
             mEnterTransitionCoordinator.stop();
             mEnterTransitionCoordinator = null;
         }
@@ -275,6 +280,7 @@
                         restoreReenteringViews();
                     } else if (mEnterTransitionCoordinator.isReturning()) {
                         mEnterTransitionCoordinator.runAfterTransitionsComplete(() -> {
+                            getPendingExitNames(); // Set mPendingExitNames before clearing
                             mEnterTransitionCoordinator = null;
                         });
                     }
@@ -374,6 +380,7 @@
     }
 
     public void startExitOutTransition(Activity activity, Bundle options) {
+        getPendingExitNames(); // Set mPendingExitNames before clearing mEnterTransitionCoordinator
         mEnterTransitionCoordinator = null;
         if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||
                 mExitTransitionCoordinators == null) {
diff --git a/core/java/android/app/AppOpInfo.java b/core/java/android/app/AppOpInfo.java
index 979c910..5268ec4 100644
--- a/core/java/android/app/AppOpInfo.java
+++ b/core/java/android/app/AppOpInfo.java
@@ -26,6 +26,7 @@
  * Information about a particular app op.
  */
 class AppOpInfo {
+
     /**
      * A unique constant identifying this app op.
      */
@@ -91,6 +92,11 @@
      */
     public final boolean restrictRead;
 
+    /**
+     * Whether to collect noteOp instances, and send them to callbacks.
+     */
+    public final boolean forceCollectNotes;
+
     AppOpInfo(int code,
             int switchCode,
             @NonNull String name,
@@ -100,7 +106,8 @@
             AppOpsManager.RestrictionBypass allowSystemRestrictionBypass,
             int defaultMode,
             boolean disableReset,
-            boolean restrictRead) {
+            boolean restrictRead,
+            boolean forceCollectNotes) {
         if (code < OP_NONE) throw new IllegalArgumentException();
         if (switchCode < OP_NONE) throw new IllegalArgumentException();
         Objects.requireNonNull(name);
@@ -115,6 +122,7 @@
         this.defaultMode = defaultMode;
         this.disableReset = disableReset;
         this.restrictRead = restrictRead;
+        this.forceCollectNotes = forceCollectNotes;
     }
 
     static class Builder {
@@ -128,6 +136,7 @@
         private int mDefaultMode = AppOpsManager.MODE_DEFAULT;
         private boolean mDisableReset = false;
         private boolean mRestrictRead = false;
+        private boolean mForceCollectNotes = false;
 
         Builder(int code, @NonNull String name, @NonNull String simpleName) {
             if (code < OP_NONE) throw new IllegalArgumentException();
@@ -190,9 +199,15 @@
             return this;
         }
 
+        public Builder setForceCollectNotes(boolean value) {
+            this.mForceCollectNotes = value;
+            return this;
+        }
+
         public AppOpInfo build() {
             return new AppOpInfo(mCode, mSwitchCode, mName, mSimpleName, mPermission, mRestriction,
-                mAllowSystemRestrictionBypass, mDefaultMode, mDisableReset, mRestrictRead);
+                mAllowSystemRestrictionBypass, mDefaultMode, mDisableReset, mRestrictRead,
+                    mForceCollectNotes);
         }
     }
 }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index bc59d60..28404d5 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -554,7 +554,7 @@
      * @hide
      */
     public static int resolveFirstUnrestrictedUidState(int op) {
-        return UID_STATE_FOREGROUND;
+        return UID_STATE_MAX_LAST_NON_RESTRICTED;
     }
 
     /**
@@ -1831,6 +1831,9 @@
     })
     private @interface ShouldCollectNoteOp {}
 
+    /** Whether noting for an appop should be collected */
+    private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
+
     private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
             // RUNTIME PERMISSIONS
             // Contacts
@@ -2281,10 +2284,19 @@
                 "ACCESS_RESTRICTED_SETTINGS").setDefaultMode(AppOpsManager.MODE_ALLOWED)
             .setDisableReset(true).setRestrictRead(true).build(),
         new AppOpInfo.Builder(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
-                "RECEIVE_SOUNDTRIGGER_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
+                "RECEIVE_SOUNDTRIGGER_AUDIO").setDefaultMode(AppOpsManager.MODE_ALLOWED)
+                .setForceCollectNotes(true).build()
     };
 
     /**
+     * @hide
+     */
+    public static boolean shouldForceCollectNoteForOp(int op) {
+        Preconditions.checkArgumentInRange(op, 0, _NUM_OP - 1, "opCode");
+        return sAppOpInfos[op].forceCollectNotes;
+    }
+
+    /**
      * Mapping from an app op name to the app op code.
      */
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<>();
@@ -2313,9 +2325,6 @@
     private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
             new ThreadLocal<>();
 
-    /** Whether noting for an appop should be collected */
-    private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
-
     static {
         if (sAppOpInfos.length != _NUM_OP) {
             throw new IllegalStateException("mAppOpInfos length " + sAppOpInfos.length
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 93381cf..81f6143 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -258,6 +258,11 @@
  * pressing back will pop it to return the user to whatever previous state
  * the activity UI was in.
  *
+ * <p>
+ * Fragments appearing or disappearing do not generate system events for accessibility, so set a
+ * title on your fragments with {@link View#setAccessibilityPaneTitle(CharSequence)} to notify
+ * accessibility users of these UI transitions.
+ *
  * @deprecated Use the <a href="{@docRoot}jetpack">Jetpack Fragment Library</a>
  *      {@link androidx.fragment.app.Fragment} for consistent behavior across all devices
  *      and access to <a href="{@docRoot}topic/libraries/architecture/lifecycle.html">Lifecycle</a>.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index bd999fc..980b79b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -522,9 +522,6 @@
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     boolean stopBinderTrackingAndDump(in ParcelFileDescriptor fd);
 
-    /** Enables server-side binder tracing for the calling uid. */
-    void enableBinderTracing();
-
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     void suppressResizeConfigChanges(boolean suppress);
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
@@ -769,6 +766,8 @@
      *
      * <p>Typically used only by automotive builds when the vehicle has multiple displays.
      */
+    @JavaPassthrough(annotation=
+            "@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional = true)")
     boolean startUserInBackgroundOnSecondaryDisplay(int userid, int displayId);
 
 }
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 2b245aa..5c29eb3 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -95,8 +95,11 @@
         } else {
             mId = null;
         }
-        mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mName = getTrimmedString(mName.toString());
+        if (in.readByte() != 0) {
+            mName = getTrimmedString(in.readString());
+        } else {
+            mName = "";
+        }
         if (in.readByte() != 0) {
             mDescription = getTrimmedString(in.readString());
         } else {
@@ -122,7 +125,12 @@
         } else {
             dest.writeByte((byte) 0);
         }
-        TextUtils.writeToParcel(mName.toString(), dest, flags);
+        if (mName != null) {
+            dest.writeByte((byte) 1);
+            dest.writeString(mName.toString());
+        } else {
+            dest.writeByte((byte) 0);
+        }
         if (mDescription != null) {
             dest.writeByte((byte) 1);
             dest.writeString(mDescription);
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 13934e5..a51b9d3 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -391,7 +391,12 @@
     private static final boolean DEBUG = false;
     private static final boolean VERIFY = false;
 
-    // Per-Cache performance counters. As some cache instances are declared static,
+    /**
+     * The object-private lock.
+     */
+    private final Object mLock = new Object();
+
+    // Per-Cache performance counters.
     @GuardedBy("mLock")
     private long mHits = 0;
 
@@ -410,27 +415,21 @@
     @GuardedBy("mLock")
     private long mClears = 0;
 
-    // Most invalidation is done in a static context, so the counters need to be accessible.
-    @GuardedBy("sCorkLock")
-    private static final HashMap<String, Long> sInvalidates = new HashMap<>();
+    /**
+     * Protect objects that support corking.  mLock and sGlobalLock must never be taken while this
+     * is held.
+     */
+    private static final Object sCorkLock = new Object();
 
     /**
-     * Record the number of invalidate or cork calls that were nops because
-     * the cache was already corked.  This is static because invalidation is
-     * done in a static context.
+     * Record the number of invalidate or cork calls that were nops because the cache was already
+     * corked.  This is static because invalidation is done in a static context.  Entries are
+     * indexed by the cache property.
      */
     @GuardedBy("sCorkLock")
     private static final HashMap<String, Long> sCorkedInvalidates = new HashMap<>();
 
     /**
-     * If sEnabled is false then all cache operations are stubbed out.  Set
-     * it to false inside test processes.
-     */
-    private static boolean sEnabled = true;
-
-    private static final Object sCorkLock = new Object();
-
-    /**
      * A map of cache keys that we've "corked". (The values are counts.)  When a cache key is
      * corked, we skip the cache invalidate when the cache key is in the unset state --- that
      * is, when a cache key is corked, an invalidation does not enable the cache if somebody
@@ -440,21 +439,39 @@
     private static final HashMap<String, Integer> sCorks = new HashMap<>();
 
     /**
+     * A lock for the global list of caches and cache keys.  This must never be taken inside mLock
+     * or sCorkLock.
+     */
+    private static final Object sGlobalLock = new Object();
+
+    /**
      * A map of cache keys that have been disabled in the local process.  When a key is
      * disabled locally, existing caches are disabled and the key is saved in this map.
      * Future cache instances that use the same key will be disabled in their constructor.
      */
-    @GuardedBy("sCorkLock")
+    @GuardedBy("sGlobalLock")
     private static final HashSet<String> sDisabledKeys = new HashSet<>();
 
     /**
      * Weakly references all cache objects in the current process, allowing us to iterate over
      * them all for purposes like issuing debug dumps and reacting to memory pressure.
      */
-    @GuardedBy("sCorkLock")
+    @GuardedBy("sGlobalLock")
     private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches = new WeakHashMap<>();
 
-    private final Object mLock = new Object();
+    /**
+     * Counts of the number of times a cache key was invalidated.  Invalidation occurs in a static
+     * context with no cache object available, so this is a static map.  Entries are indexed by
+     * the cache property.
+     */
+    @GuardedBy("sGlobalLock")
+    private static final HashMap<String, Long> sInvalidates = new HashMap<>();
+
+    /**
+     * If sEnabled is false then all cache operations are stubbed out.  Set
+     * it to false inside test processes.
+     */
+    private static boolean sEnabled = true;
 
     /**
      * Name of the property that holds the unique value that we use to invalidate the cache.
@@ -595,14 +612,17 @@
         };
     }
 
-    // Register the map in the global list.  If the cache is disabled globally, disable it
-    // now.
+    /**
+     * Register the map in the global list.  If the cache is disabled globally, disable it
+     * now.  This method is only ever called from the constructor, which means no other thread has
+     * access to the object yet.  It can safely be modified outside any lock.
+     */
     private void registerCache() {
-        synchronized (sCorkLock) {
-            sCaches.put(this, null);
+        synchronized (sGlobalLock) {
             if (sDisabledKeys.contains(mCacheName)) {
                 disableInstance();
             }
+            sCaches.put(this, null);
         }
     }
 
@@ -797,8 +817,9 @@
     }
 
     /**
-     * Disable the use of this cache in this process.  This method is using during
-     * testing.  To disable a cache in normal code, use disableLocal().
+     * Disable the use of this cache in this process.  This method is using internally and during
+     * testing.  To disable a cache in normal code, use disableLocal().  A disabled cache cannot
+     * be re-enabled.
      * @hide
      */
     @TestApi
@@ -811,17 +832,23 @@
 
     /**
      * Disable the local use of all caches with the same name.  All currently registered caches
-     * using the key will be disabled now, and all future cache instances that use the key will be
-     * disabled in their constructor.
+     * with the name will be disabled now, and all future cache instances that use the name will
+     * be disabled in their constructor.
      */
     private static final void disableLocal(@NonNull String name) {
-        synchronized (sCorkLock) {
-            sDisabledKeys.add(name);
+        synchronized (sGlobalLock) {
+            if (sDisabledKeys.contains(name)) {
+                // The key is already in recorded so there is no further work to be done.
+                return;
+            }
             for (PropertyInvalidatedCache cache : sCaches.keySet()) {
                 if (name.equals(cache.mCacheName)) {
                     cache.disableInstance();
                 }
             }
+            // Record the disabled key after the iteration.  If an exception occurs during the
+            // iteration above, and the code is retried, the function should not exit early.
+            sDisabledKeys.add(name);
         }
     }
 
@@ -834,7 +861,7 @@
      */
     @TestApi
     public final void forgetDisableLocal() {
-        synchronized (sCorkLock) {
+        synchronized (sGlobalLock) {
             sDisabledKeys.remove(mCacheName);
         }
     }
@@ -851,9 +878,9 @@
     }
 
     /**
-     * Disable this cache in the current process, and all other caches that use the same
-     * name.  This does not affect caches that have a different name but use the same
-     * property.
+     * Disable this cache in the current process, and all other present and future caches that use
+     * the same name.  This does not affect caches that have a different name but use the same
+     * property.  Once disabled, a cache cannot be reenabled.
      * @hide
      */
     @TestApi
@@ -1381,10 +1408,9 @@
     /**
      * Returns a list of caches alive at the current time.
      */
+    @GuardedBy("sGlobalLock")
     private static @NonNull ArrayList<PropertyInvalidatedCache> getActiveCaches() {
-        synchronized (sCorkLock) {
-            return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
-        }
+        return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
     }
 
     /**
@@ -1540,7 +1566,7 @@
         boolean detail = anyDetailed(args);
 
         ArrayList<PropertyInvalidatedCache> activeCaches;
-        synchronized (sCorkLock) {
+        synchronized (sGlobalLock) {
             activeCaches = getActiveCaches();
             if (!detail) {
                 dumpCorkInfo(pw);
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 8d57e32..d17f2ba 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -45,6 +45,7 @@
 import android.view.WindowContentFrameStats;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.IAccessibilityManager;
+import android.window.ScreenCapture;
 
 import libcore.io.IoUtils;
 
@@ -220,13 +221,13 @@
             int width = crop.width();
             int height = crop.height();
             final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-            final SurfaceControl.DisplayCaptureArgs captureArgs =
-                    new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+            final ScreenCapture.DisplayCaptureArgs captureArgs =
+                    new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
                             .setSourceCrop(crop)
                             .setSize(width, height)
                             .build();
-            final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                    SurfaceControl.captureDisplay(captureArgs);
+            final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                    ScreenCapture.captureDisplay(captureArgs);
             return screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -242,11 +243,11 @@
             throwIfNotConnectedLocked();
         }
 
-        SurfaceControl.ScreenshotHardwareBuffer captureBuffer;
+        ScreenCapture.ScreenshotHardwareBuffer captureBuffer;
         final long identity = Binder.clearCallingIdentity();
         try {
-            captureBuffer = SurfaceControl.captureLayers(
-                    new SurfaceControl.LayerCaptureArgs.Builder(surfaceControl)
+            captureBuffer = ScreenCapture.captureLayers(
+                    new ScreenCapture.LayerCaptureArgs.Builder(surfaceControl)
                             .setChildrenOnly(false)
                             .build());
         } finally {
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 397c8e0..39d77c4 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -462,14 +462,31 @@
 
     /** @hide */
     public void scale(float scale) {
-        mBounds.scale(scale);
-        mMaxBounds.scale(scale);
+        scaleBounds(scale, mBounds);
+        scaleBounds(scale, mMaxBounds);
         if (mAppBounds != null) {
-            mAppBounds.scale(scale);
+            scaleBounds(scale, mAppBounds);
         }
     }
 
     /**
+     * Size based scaling. This avoid inconsistent length when rounding 4 sides.
+     * E.g. left=12, right=18, scale=0.8. The scaled width can be:
+     *   int((right - left) * scale + 0.5) = int(4.8 + 0.5) = 5
+     * But with rounding both left and right, the width will be inconsistent:
+     *   int(right * scale + 0.5) - int(left * scale + 0.5) = int(14.9) - int(10.1) = 4
+     * @hide
+     */
+    private static void scaleBounds(float scale, Rect bounds) {
+        final int w = bounds.width();
+        final int h = bounds.height();
+        bounds.left = (int) (bounds.left * scale + .5f);
+        bounds.top = (int) (bounds.top * scale + .5f);
+        bounds.right = bounds.left + (int) (w * scale + .5f);
+        bounds.bottom = bounds.top + (int) (h * scale + .5f);
+    }
+
+    /**
      * Copies the fields from delta into this Configuration object, keeping
      * track of which ones have changed. Any undefined fields in {@code delta}
      * are ignored and not copied in to the current Configuration.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5875e2d..ab11d6a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8689,7 +8689,6 @@
      * and no accounts.
      *
      * @param who the component name to be registered as device owner.
-     * @param ownerName the human readable name of the institution that owns this device.
      * @param userId ID of the user on which the device owner runs.
      *
      * @return whether the package was successfully registered as the device owner.
@@ -8701,11 +8700,10 @@
      */
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
-    public boolean setDeviceOwner(@NonNull ComponentName who, @Nullable String ownerName,
-            @UserIdInt int userId) {
+    public boolean setDeviceOwner(@NonNull ComponentName who, @UserIdInt int userId) {
         if (mService != null) {
             try {
-                return mService.setDeviceOwner(who, ownerName, userId,
+                return mService.setDeviceOwner(who, userId,
                         /* setProfileOwnerOnCurrentUserIfNecessary= */ true);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
@@ -8715,7 +8713,7 @@
     }
 
     /**
-     * Same as {@link #setDeviceOwner(ComponentName, String, int)}, but without setting the profile
+     * Same as {@link #setDeviceOwner(ComponentName, int)}, but without setting the profile
      * owner on current user when running on headless system user mode - should be used only by
      * testing infra.
      *
@@ -8724,10 +8722,10 @@
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public boolean setDeviceOwnerOnly(
-            @NonNull ComponentName who, @Nullable String ownerName, @UserIdInt int userId) {
+            @NonNull ComponentName who, @UserIdInt int userId) {
         if (mService != null) {
             try {
-                return mService.setDeviceOwner(who, ownerName, userId,
+                return mService.setDeviceOwner(who, userId,
                         /* setProfileOwnerOnCurrentUserIfNecessary= */ false);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
@@ -8971,7 +8969,7 @@
             try {
                 final int myUserId = myUserId();
                 mService.setActiveAdmin(admin, false, myUserId);
-                return mService.setProfileOwner(admin, ownerName, myUserId);
+                return mService.setProfileOwner(admin, myUserId);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
@@ -9033,20 +9031,16 @@
      * - the caller is SYSTEM_UID.
      * - or the caller is the shell uid, and there are no accounts on the specified user.
      * @param admin the component name to be registered as profile owner.
-     * @param ownerName the human readable name of the organisation associated with this DPM.
      * @param userHandle the userId to set the profile owner for.
      * @return whether the component was successfully registered as the profile owner.
      * @throws IllegalArgumentException if admin is null, the package isn't installed, or the
      * preconditions mentioned are not met.
      */
-    public boolean setProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName,
-            int userHandle) throws IllegalArgumentException {
+    public boolean setProfileOwner(@NonNull ComponentName admin, int userHandle)
+            throws IllegalArgumentException {
         if (mService != null) {
             try {
-                if (ownerName == null) {
-                    ownerName = "";
-                }
-                return mService.setProfileOwner(admin, ownerName, userHandle);
+                return mService.setProfileOwner(admin, userHandle);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
@@ -15429,7 +15423,7 @@
      *
      * @see #setWifiSsidPolicy(WifiSsidPolicy)
      * @throws SecurityException if the caller is not a device owner or a profile owner on
-     * an organization-owned managed profile or a system app.
+     * an organization-owned managed profile.
      */
     @Nullable
     public WifiSsidPolicy getWifiSsidPolicy() {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fea7770..75bfc25 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -168,14 +168,14 @@
     void reportKeyguardDismissed(int userHandle);
     void reportKeyguardSecured(int userHandle);
 
-    boolean setDeviceOwner(in ComponentName who, String ownerName, int userId, boolean setProfileOwnerOnCurrentUserIfNecessary);
+    boolean setDeviceOwner(in ComponentName who, int userId, boolean setProfileOwnerOnCurrentUserIfNecessary);
     ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
     boolean hasDeviceOwner();
     String getDeviceOwnerName();
     void clearDeviceOwner(String packageName);
     int getDeviceOwnerUserId();
 
-    boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
+    boolean setProfileOwner(in ComponentName who, int userHandle);
     ComponentName getProfileOwnerAsUser(int userHandle);
     ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(in UserHandle userHandle);
     boolean isSupervisionComponent(in ComponentName who);
diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java
index af48fde..865e1fb 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEvent.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java
@@ -63,8 +63,6 @@
      * The integer indicating a double-tap event was detected.
      * For detecting this event type, there's no specific consent activity to request access, but
      * the consent is implied through the double tap toggle in the Settings app.
-     *
-     * @hide
      */
     public static final int EVENT_BACK_DOUBLE_TAP = 3;
 
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index 5a3ad31..1c490be 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -40,6 +41,7 @@
 
     @Override
     public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
         // Notify the client of an upcoming change in the token configuration. This ensures that
         // batches of config change items only process the newest configuration.
         client.updatePendingActivityConfiguration(token, mConfiguration);
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
index b3e34b3..c09461c 100644
--- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -23,6 +23,7 @@
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
 import android.app.ResultInfo;
+import android.content.res.CompatibilityInfo;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Trace;
@@ -56,6 +57,7 @@
 
     @Override
     public void preExecute(ClientTransactionHandler client, IBinder token) {
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig);
         mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
                 mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
     }
diff --git a/core/java/android/app/servertransaction/ConfigurationChangeItem.java b/core/java/android/app/servertransaction/ConfigurationChangeItem.java
index 2acff49..49a1c66 100644
--- a/core/java/android/app/servertransaction/ConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ConfigurationChangeItem.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.app.ClientTransactionHandler;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -34,6 +35,7 @@
 
     @Override
     public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
         client.updatePendingConfiguration(mConfiguration);
     }
 
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 03d6e27..7e4db81 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -30,6 +30,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.BaseBundle;
 import android.os.Bundle;
@@ -81,6 +82,8 @@
     public void preExecute(ClientTransactionHandler client, IBinder token) {
         client.countLaunchingActivities(1);
         client.updateProcessState(mProcState, false);
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mCurConfig);
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mOverrideConfig);
         client.updatePendingConfiguration(mCurConfig);
         if (mActivityClientController != null) {
             ActivityClient.setActivityClientController(mActivityClientController);
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 2893ff2..f13bd74 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -40,6 +41,7 @@
 
     @Override
     public void preExecute(ClientTransactionHandler client, IBinder token) {
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mConfiguration);
         // Notify the client of an upcoming change in the token configuration. This ensures that
         // batches of config change items only process the newest configuration.
         client.updatePendingActivityConfiguration(token, mConfiguration);
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index ef5f84c..a30fd33 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -43,7 +43,7 @@
     private BluetoothDeviceFilterUtils() {}
 
     private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "BluetoothDeviceFilterUtils";
+    private static final String LOG_TAG = "CDM_BluetoothDeviceFilterUtils";
 
     @Nullable
     static String patternToString(@Nullable Pattern p) {
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index 2934cd2..b178699 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -54,7 +54,7 @@
 public final class BluetoothLeDeviceFilter implements DeviceFilter<ScanResult> {
 
     private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "BluetoothLeDeviceFilter";
+    private static final String LOG_TAG = "CDM_BluetoothLeDeviceFilter";
 
     private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
 
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index c1a3c19..357bf59 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -81,7 +81,7 @@
 public final class CompanionDeviceManager {
 
     private static final boolean DEBUG = false;
-    private static final String LOG_TAG = "CompanionDeviceManager";
+    private static final String LOG_TAG = "CDM_CompanionDeviceManager";
 
     /**
      * The result code to propagate back to the originating activity, indicates the association
@@ -709,27 +709,29 @@
     /**
      * Register to receive callbacks whenever the associated device comes in and out of range.
      *
-     * The provided device must be {@link #associate associated} with the calling app before
-     * calling this method.
+     * <p>The provided device must be {@link #associate associated} with the calling app before
+     * calling this method.</p>
      *
-     * Caller must implement a single {@link CompanionDeviceService} which will be bound to and
+     * <p>Caller must implement a single {@link CompanionDeviceService} which will be bound to and
      * receive callbacks to {@link CompanionDeviceService#onDeviceAppeared} and
      * {@link CompanionDeviceService#onDeviceDisappeared}.
-     * The app doesn't need to remain running in order to receive its callbacks.
+     * The app doesn't need to remain running in order to receive its callbacks.</p>
      *
-     * Calling app must declare uses-permission
-     * {@link android.Manifest.permission#REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE}.
+     * <p>Calling app must declare uses-permission
+     * {@link android.Manifest.permission#REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE}.</p>
      *
-     * Calling app must check for feature presence of
-     * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} before calling this API.
+     * <p>Calling app must check for feature presence of
+     * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} before calling this API.</p>
      *
-     * For Bluetooth LE devices this is based on scanning for device with the given address.
-     * For Bluetooth classic devices this is triggered when the device connects/disconnects.
-     * WiFi devices are not supported.
+     * <p>For Bluetooth LE devices, this is based on scanning for device with the given address.
+     * The system will scan for the device when Bluetooth is ON or Bluetooth scanning is ON.</p>
      *
-     * If a Bluetooth LE device wants to use a rotating mac address, it is recommended to use
+     * <p>For Bluetooth classic devices this is triggered when the device connects/disconnects.
+     * WiFi devices are not supported.</p>
+     *
+     * <p>If a Bluetooth LE device wants to use a rotating mac address, it is recommended to use
      * Resolvable Private Address, and ensure the device is bonded to the phone so that android OS
-     * is able to resolve the address.
+     * is able to resolve the address.</p>
      *
      * @param deviceAddress a previously-associated companion device's address
      *
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index a79983a..3a7dd8e 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -99,7 +99,7 @@
  */
 public abstract class CompanionDeviceService extends Service {
 
-    private static final String LOG_TAG = "CompanionDeviceService";
+    private static final String LOG_TAG = "CDM_CompanionDeviceService";
 
     /**
      * An intent action for a service to be bound whenever this app's companion device(s)
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index e146bb9..6ce2242 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -29,6 +29,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.DisplayMetrics;
+import android.util.MergedConfiguration;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.MotionEvent;
@@ -111,6 +112,9 @@
      */
     public final float applicationInvertedScale;
 
+    /** The process level override inverted scale. See {@link #HAS_OVERRIDE_SCALING}. */
+    private static float sOverrideInvertedScale = 1f;
+
     @UnsupportedAppUsage
     @Deprecated
     public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw,
@@ -125,6 +129,15 @@
         if (appInfo.targetSdkVersion < VERSION_CODES.O) {
             compatFlags |= NEEDS_COMPAT_RES;
         }
+        if (overrideScale != 1.0f) {
+            applicationScale = overrideScale;
+            applicationInvertedScale = 1.0f / overrideScale;
+            applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE
+                    * applicationInvertedScale) + .5f);
+            mCompatibilityFlags = NEVER_NEEDS_COMPAT | HAS_OVERRIDE_SCALING;
+            // Override scale has the highest priority. So ignore other compatibility attributes.
+            return;
+        }
         if (appInfo.requiresSmallestWidthDp != 0 || appInfo.compatibleWidthLimitDp != 0
                 || appInfo.largestWidthLimitDp != 0) {
             // New style screen requirements spec.
@@ -254,13 +267,7 @@
                 compatFlags |= NEVER_NEEDS_COMPAT;
             }
 
-            if (overrideScale != 1.0f) {
-                applicationScale = overrideScale;
-                applicationInvertedScale = 1.0f / overrideScale;
-                applicationDensity = (int) ((DisplayMetrics.DENSITY_DEVICE_STABLE
-                        * applicationInvertedScale) + .5f);
-                compatFlags |= HAS_OVERRIDE_SCALING;
-            } else if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+            if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
                 applicationDensity = DisplayMetrics.DENSITY_DEVICE;
                 applicationScale = 1.0f;
                 applicationInvertedScale = 1.0f;
@@ -296,9 +303,14 @@
      */
     @UnsupportedAppUsage
     public boolean isScalingRequired() {
-        return (mCompatibilityFlags & (SCALING_REQUIRED | HAS_OVERRIDE_SCALING)) != 0;
+        return (mCompatibilityFlags & SCALING_REQUIRED) != 0;
     }
-    
+
+    /** Returns {@code true} if {@link #sOverrideInvertedScale} should be set. */
+    public boolean hasOverrideScaling() {
+        return (mCompatibilityFlags & HAS_OVERRIDE_SCALING) != 0;
+    }
+
     @UnsupportedAppUsage
     public boolean supportsScreen() {
         return (mCompatibilityFlags&NEEDS_SCREEN_COMPAT) == 0;
@@ -513,7 +525,19 @@
         }
     }
 
+    /** Applies the compatibility adjustment to the display metrics. */
+    public void applyDisplayMetricsIfNeeded(DisplayMetrics inoutDm, boolean applyToSize) {
+        if (hasOverrideScale()) {
+            scaleDisplayMetrics(sOverrideInvertedScale, inoutDm, applyToSize);
+            return;
+        }
+        if (!equals(DEFAULT_COMPATIBILITY_INFO)) {
+            applyToDisplayMetrics(inoutDm);
+        }
+    }
+
     public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
+        if (hasOverrideScale()) return;
         if (!supportsScreen()) {
             // This is a larger screen device and the app is not
             // compatible with large screens, so diddle it.
@@ -524,18 +548,26 @@
         }
 
         if (isScalingRequired()) {
-            float invertedRatio = applicationInvertedScale;
-            inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
-            inoutDm.densityDpi = (int)((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
-            inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
-            inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
-            inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
+            scaleDisplayMetrics(applicationInvertedScale, inoutDm, true /* applyToSize */);
+        }
+    }
+
+    /** Scales the density of the given display metrics. */
+    private static void scaleDisplayMetrics(float invertedRatio, DisplayMetrics inoutDm,
+            boolean applyToSize) {
+        inoutDm.density = inoutDm.noncompatDensity * invertedRatio;
+        inoutDm.densityDpi = (int) ((inoutDm.noncompatDensityDpi * invertedRatio) + .5f);
+        inoutDm.scaledDensity = inoutDm.noncompatScaledDensity * invertedRatio;
+        inoutDm.xdpi = inoutDm.noncompatXdpi * invertedRatio;
+        inoutDm.ydpi = inoutDm.noncompatYdpi * invertedRatio;
+        if (applyToSize) {
             inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
             inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
         }
     }
 
     public void applyToConfiguration(int displayDensity, Configuration inoutConfig) {
+        if (hasOverrideScale()) return;
         if (!supportsScreen()) {
             // This is a larger screen device and the app is not
             // compatible with large screens, so we are forcing it to
@@ -549,12 +581,45 @@
         }
         inoutConfig.densityDpi = displayDensity;
         if (isScalingRequired()) {
-            float invertedRatio = applicationInvertedScale;
-            inoutConfig.densityDpi = (int)((inoutConfig.densityDpi * invertedRatio) + .5f);
-            inoutConfig.windowConfiguration.scale(invertedRatio);
+            scaleConfiguration(applicationInvertedScale, inoutConfig);
         }
     }
 
+    /** Scales the density and bounds of the given configuration. */
+    public static void scaleConfiguration(float invertedRatio, Configuration inoutConfig) {
+        inoutConfig.densityDpi = (int) ((inoutConfig.densityDpi * invertedRatio) + .5f);
+        inoutConfig.windowConfiguration.scale(invertedRatio);
+    }
+
+    /** @see #sOverrideInvertedScale */
+    public static void applyOverrideScaleIfNeeded(Configuration config) {
+        if (!hasOverrideScale()) return;
+        scaleConfiguration(sOverrideInvertedScale, config);
+    }
+
+    /** @see #sOverrideInvertedScale */
+    public static void applyOverrideScaleIfNeeded(MergedConfiguration mergedConfig) {
+        if (!hasOverrideScale()) return;
+        scaleConfiguration(sOverrideInvertedScale, mergedConfig.getGlobalConfiguration());
+        scaleConfiguration(sOverrideInvertedScale, mergedConfig.getOverrideConfiguration());
+        scaleConfiguration(sOverrideInvertedScale, mergedConfig.getMergedConfiguration());
+    }
+
+    /** Returns {@code true} if this process is in a environment with override scale. */
+    private static boolean hasOverrideScale() {
+        return sOverrideInvertedScale != 1f;
+    }
+
+    /** @see #sOverrideInvertedScale */
+    public static void setOverrideInvertedScale(float invertedRatio) {
+        sOverrideInvertedScale = invertedRatio;
+    }
+
+    /** @see #sOverrideInvertedScale */
+    public static float getOverrideInvertedScale() {
+        return sOverrideInvertedScale;
+    }
+
     /**
      * Compute the frame Rect for applications runs under compatibility mode.
      *
@@ -632,6 +697,10 @@
             sb.append(applicationScale);
             sb.append("x");
         }
+        if (hasOverrideScaling()) {
+            sb.append(" overrideInvScale=");
+            sb.append(applicationInvertedScale);
+        }
         if (!supportsScreen()) {
             sb.append(" resizing");
         }
diff --git a/core/java/android/ddm/DdmHandleViewDebug.java b/core/java/android/ddm/DdmHandleViewDebug.java
index 6b0f78f..0f66fcb 100644
--- a/core/java/android/ddm/DdmHandleViewDebug.java
+++ b/core/java/android/ddm/DdmHandleViewDebug.java
@@ -16,12 +16,16 @@
 
 package android.ddm;
 
+import static com.android.internal.util.Preconditions.checkArgument;
+
 import android.util.Log;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewRootImpl;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import org.apache.harmony.dalvik.ddmc.Chunk;
 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
 import org.apache.harmony.dalvik.ddmc.DdmServer;
@@ -34,6 +38,7 @@
 import java.lang.reflect.Method;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Handle various requests related to profiling / debugging of the view system.
@@ -123,14 +128,15 @@
         }
 
         if (type == CHUNK_VURT) {
-            if (op == VURT_DUMP_HIERARCHY)
+            if (op == VURT_DUMP_HIERARCHY) {
                 return dumpHierarchy(rootView, in);
-            else if (op == VURT_CAPTURE_LAYERS)
+            } else if (op == VURT_CAPTURE_LAYERS) {
                 return captureLayers(rootView);
-            else if (op == VURT_DUMP_THEME)
+            } else if (op == VURT_DUMP_THEME) {
                 return dumpTheme(rootView);
-            else
+            } else {
                 return createFailChunk(ERR_INVALID_OP, "Unknown view root operation: " + op);
+            }
         }
 
         final View targetView = getTargetView(rootView, in);
@@ -207,9 +213,9 @@
     /**
      * Returns the view hierarchy and/or view properties starting at the provided view.
      * Based on the input options, the return data may include:
-     *  - just the view hierarchy
-     *  - view hierarchy & the properties for each of the views
-     *  - just the view properties for a specific view.
+     * - just the view hierarchy
+     * - view hierarchy & the properties for each of the views
+     * - just the view properties for a specific view.
      *  TODO: Currently this only returns views starting at the root, need to fix so that
      *  it can return properties of any view.
      */
@@ -220,7 +226,7 @@
 
         long start = System.currentTimeMillis();
 
-        ByteArrayOutputStream b = new ByteArrayOutputStream(2*1024*1024);
+        ByteArrayOutputStream b = new ByteArrayOutputStream(2 * 1024 * 1024);
         try {
             if (v2) {
                 ViewDebug.dumpv2(rootView, b);
@@ -304,17 +310,47 @@
      * Invokes provided method on the view.
      * The method name and its arguments are passed in as inputs via the byte buffer.
      * The buffer contains:<ol>
-     *  <li> len(method name) </li>
-     *  <li> method name </li>
-     *  <li> # of args </li>
-     *  <li> arguments: Each argument comprises of a type specifier followed by the actual argument.
-     *          The type specifier is a single character as used in JNI:
-     *          (Z - boolean, B - byte, C - char, S - short, I - int, J - long,
-     *          F - float, D - double). <p>
-     *          The type specifier is followed by the actual value of argument.
-     *          Booleans are encoded via bytes with 0 indicating false.</li>
+     * <li> len(method name) </li>
+     * <li> method name (encoded as UTF-16 2-byte characters) </li>
+     * <li> # of args </li>
+     * <li> arguments: Each argument comprises of a type specifier followed by the actual argument.
+     * The type specifier is one character modelled after JNI signatures:
+     *          <ul>
+     *              <li>[ - array<br>
+     *                This is followed by a second character according to this spec, indicating the
+     *                array type, then the array length as an Int, followed by a repeated encoding
+     *                of the actual data.
+     *                WARNING: Only <b>byte[]</b> is supported currently.
+     *              </li>
+     *              <li>Z - boolean<br>
+     *                 Booleans are encoded via bytes with 0 indicating false</li>
+     *              <li>B - byte</li>
+     *              <li>C - char</li>
+     *              <li>S - short</li>
+     *              <li>I - int</li>
+     *              <li>J - long</li>
+     *              <li>F - float</li>
+     *              <li>D - double</li>
+     *              <li>V - void<br>
+     *                NOT followed by a value. Only used for return types</li>
+     *              <li>R - String (not a real JNI type, but added for convenience)<br>
+     *                Strings are encoded as an unsigned short of the number of <b>bytes</b>,
+     *                followed by the actual UTF-8 encoded bytes.
+     *                WARNING: This is the same encoding as produced by
+     *                ViewHierarchyEncoder#writeString. However, note that this encoding is
+     *                different to what DdmHandle#getString() expects, which is used in other places
+     *                in this class.
+     *                WARNING: Since the length is the number of UTF-8 encoded bytes, Strings can
+     *                contain up to 64k ASCII characters, yet depending on the actual data, the true
+     *                maximum might be as little as 21844 unicode characters.
+     *                <b>null</b> String objects are encoded as an empty string
+     *              </li>
+     *            </ul>
+     *   </li>
      * </ol>
      * Methods that take no arguments need only specify the method name.
+     *
+     * The return value is encoded the same way as a single parameter (type + value)
      */
     private Chunk invokeViewMethod(final View rootView, final View targetView, ByteBuffer in) {
         int l = in.getInt();
@@ -327,54 +363,17 @@
             args = new Object[0];
         } else {
             int nArgs = in.getInt();
-
             argTypes = new Class<?>[nArgs];
             args = new Object[nArgs];
 
-            for (int i = 0; i < nArgs; i++) {
-                char c = in.getChar();
-                switch (c) {
-                    case 'Z':
-                        argTypes[i] = boolean.class;
-                        args[i] = in.get() == 0 ? false : true;
-                        break;
-                    case 'B':
-                        argTypes[i] = byte.class;
-                        args[i] = in.get();
-                        break;
-                    case 'C':
-                        argTypes[i] = char.class;
-                        args[i] = in.getChar();
-                        break;
-                    case 'S':
-                        argTypes[i] = short.class;
-                        args[i] = in.getShort();
-                        break;
-                    case 'I':
-                        argTypes[i] = int.class;
-                        args[i] = in.getInt();
-                        break;
-                    case 'J':
-                        argTypes[i] = long.class;
-                        args[i] = in.getLong();
-                        break;
-                    case 'F':
-                        argTypes[i] = float.class;
-                        args[i] = in.getFloat();
-                        break;
-                    case 'D':
-                        argTypes[i] = double.class;
-                        args[i] = in.getDouble();
-                        break;
-                    default:
-                        Log.e(TAG, "arg " + i + ", unrecognized type: " + c);
-                        return createFailChunk(ERR_INVALID_PARAM,
-                                "Unsupported parameter type (" + c + ") to invoke view method.");
-                }
+            try {
+                deserializeMethodParameters(args, argTypes, in);
+            } catch (ViewMethodInvocationSerializationException e) {
+                return createFailChunk(ERR_INVALID_PARAM, e.getMessage());
             }
         }
 
-        Method method = null;
+        Method method;
         try {
             method = targetView.getClass().getMethod(methodName, argTypes);
         } catch (NoSuchMethodException e) {
@@ -384,7 +383,10 @@
         }
 
         try {
-            ViewDebug.invokeViewMethod(targetView, method, args);
+            Object result = ViewDebug.invokeViewMethod(targetView, method, args);
+            Class<?> returnType = method.getReturnType();
+            byte[] returnValue = serializeReturnValue(returnType, returnType.cast(result));
+            return new Chunk(CHUNK_VUOP, returnValue, 0, returnValue.length);
         } catch (Exception e) {
             Log.e(TAG, "Exception while invoking method: " + e.getCause().getMessage());
             String msg = e.getCause().getMessage();
@@ -393,8 +395,6 @@
             }
             return createFailChunk(ERR_EXCEPTION, msg);
         }
-
-        return null;
     }
 
     private Chunk setLayoutParameter(final View rootView, final View targetView, ByteBuffer in) {
@@ -406,7 +406,7 @@
         } catch (Exception e) {
             Log.e(TAG, "Exception setting layout parameter: " + e);
             return createFailChunk(ERR_EXCEPTION, "Error accessing field "
-                        + param + ":" + e.getMessage());
+                    + param + ":" + e.getMessage());
         }
 
         return null;
@@ -431,4 +431,175 @@
         byte[] data = b.toByteArray();
         return new Chunk(CHUNK_VUOP, data, 0, data.length);
     }
+
+    /**
+     * Deserializes parameters according to the VUOP_INVOKE_VIEW_METHOD protocol the {@code in}
+     * buffer.
+     *
+     * The length of {@code args} determines how many arguments are read. The {@code argTypes} must
+     * be the same length, and will be set to the argument types of the data read.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static void deserializeMethodParameters(
+            Object[] args, Class<?>[] argTypes, ByteBuffer in) throws
+            ViewMethodInvocationSerializationException {
+        checkArgument(args.length == argTypes.length);
+
+        for (int i = 0; i < args.length; i++) {
+            char typeSignature = in.getChar();
+            boolean isArray = typeSignature == SIG_ARRAY;
+            if (isArray) {
+                char arrayType = in.getChar();
+                if (arrayType != SIG_BYTE) {
+                    // This implementation only supports byte-arrays for now.
+                    throw new ViewMethodInvocationSerializationException(
+                            "Unsupported array parameter type (" + typeSignature
+                                    + ") to invoke view method @argument " + i);
+                }
+
+                int arrayLength = in.getInt();
+                if (arrayLength > in.remaining()) {
+                    // The sender did not actually sent the specified amount of bytes. This
+                    // avoids a malformed packet to trigger an out-of-memory error.
+                    throw new BufferUnderflowException();
+                }
+
+                byte[] byteArray = new byte[arrayLength];
+                in.get(byteArray);
+
+                argTypes[i] = byte[].class;
+                args[i] = byteArray;
+            } else {
+                switch (typeSignature) {
+                    case SIG_BOOLEAN:
+                        argTypes[i] = boolean.class;
+                        args[i] = in.get() != 0;
+                        break;
+                    case SIG_BYTE:
+                        argTypes[i] = byte.class;
+                        args[i] = in.get();
+                        break;
+                    case SIG_CHAR:
+                        argTypes[i] = char.class;
+                        args[i] = in.getChar();
+                        break;
+                    case SIG_SHORT:
+                        argTypes[i] = short.class;
+                        args[i] = in.getShort();
+                        break;
+                    case SIG_INT:
+                        argTypes[i] = int.class;
+                        args[i] = in.getInt();
+                        break;
+                    case SIG_LONG:
+                        argTypes[i] = long.class;
+                        args[i] = in.getLong();
+                        break;
+                    case SIG_FLOAT:
+                        argTypes[i] = float.class;
+                        args[i] = in.getFloat();
+                        break;
+                    case SIG_DOUBLE:
+                        argTypes[i] = double.class;
+                        args[i] = in.getDouble();
+                        break;
+                    case SIG_STRING: {
+                        argTypes[i] = String.class;
+                        int stringUtf8ByteCount = Short.toUnsignedInt(in.getShort());
+                        byte[] rawStringBuffer = new byte[stringUtf8ByteCount];
+                        in.get(rawStringBuffer);
+                        args[i] = new String(rawStringBuffer, StandardCharsets.UTF_8);
+                        break;
+                    }
+                    default:
+                        Log.e(TAG, "arg " + i + ", unrecognized type: " + typeSignature);
+                        throw new ViewMethodInvocationSerializationException(
+                                "Unsupported parameter type (" + typeSignature
+                                        + ") to invoke view method.");
+                }
+            }
+
+        }
+    }
+
+    /**
+     * Serializes {@code value} to the wire protocol of VUOP_INVOKE_VIEW_METHOD.
+     * @hide
+     */
+    @VisibleForTesting
+    public static byte[] serializeReturnValue(Class<?> type, Object value)
+            throws ViewMethodInvocationSerializationException, IOException {
+        ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(1024);
+        DataOutputStream dos = new DataOutputStream(byteOutStream);
+
+        if (type.isArray()) {
+            if (!type.equals(byte[].class)) {
+                // Only byte arrays are supported currently.
+                throw new ViewMethodInvocationSerializationException(
+                        "Unsupported array return type (" + type + ")");
+            }
+            byte[] byteArray = (byte[]) value;
+            dos.writeChar(SIG_ARRAY);
+            dos.writeChar(SIG_BYTE);
+            dos.writeInt(byteArray.length);
+            dos.write(byteArray);
+        } else if (boolean.class.equals(type)) {
+            dos.writeChar(SIG_BOOLEAN);
+            dos.write((boolean) value ? 1 : 0);
+        } else if (byte.class.equals(type)) {
+            dos.writeChar(SIG_BYTE);
+            dos.writeByte((byte) value);
+        } else if (char.class.equals(type)) {
+            dos.writeChar(SIG_CHAR);
+            dos.writeChar((char) value);
+        } else if (short.class.equals(type)) {
+            dos.writeChar(SIG_SHORT);
+            dos.writeShort((short) value);
+        } else if (int.class.equals(type)) {
+            dos.writeChar(SIG_INT);
+            dos.writeInt((int) value);
+        } else if (long.class.equals(type)) {
+            dos.writeChar(SIG_LONG);
+            dos.writeLong((long) value);
+        } else if (double.class.equals(type)) {
+            dos.writeChar(SIG_DOUBLE);
+            dos.writeDouble((double) value);
+        } else if (float.class.equals(type)) {
+            dos.writeChar(SIG_FLOAT);
+            dos.writeFloat((float) value);
+        } else if (String.class.equals(type)) {
+            dos.writeChar(SIG_STRING);
+            dos.writeUTF(value != null ? (String) value : "");
+        } else {
+            dos.writeChar(SIG_VOID);
+        }
+
+        return byteOutStream.toByteArray();
+    }
+
+    // Prefixes for simple primitives. These match the JNI definitions.
+    private static final char SIG_ARRAY = '[';
+    private static final char SIG_BOOLEAN = 'Z';
+    private static final char SIG_BYTE = 'B';
+    private static final char SIG_SHORT = 'S';
+    private static final char SIG_CHAR = 'C';
+    private static final char SIG_INT = 'I';
+    private static final char SIG_LONG = 'J';
+    private static final char SIG_FLOAT = 'F';
+    private static final char SIG_DOUBLE = 'D';
+    private static final char SIG_VOID = 'V';
+    // Prefixes for some commonly used objects
+    private static final char SIG_STRING = 'R';
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public static class ViewMethodInvocationSerializationException extends Exception {
+        ViewMethodInvocationSerializationException(String message) {
+            super(message);
+        }
+    }
 }
diff --git a/core/java/android/ddm/OWNERS b/core/java/android/ddm/OWNERS
new file mode 100644
index 0000000..369025b
--- /dev/null
+++ b/core/java/android/ddm/OWNERS
@@ -0,0 +1 @@
+per-file DdmHandleViewDebug.java = michschn@google.com
diff --git a/core/java/android/hardware/BatteryState.java b/core/java/android/hardware/BatteryState.java
index aa75359..956fefc 100644
--- a/core/java/android/hardware/BatteryState.java
+++ b/core/java/android/hardware/BatteryState.java
@@ -62,7 +62,8 @@
      *
      * @return the battery status.
      */
-    public abstract @BatteryStatus int getStatus();
+    @BatteryStatus
+    public abstract int getStatus();
 
     /**
      * Get remaining battery capacity as float percentage [0.0f, 1.0f] of total capacity
@@ -70,5 +71,6 @@
      *
      * @return the battery capacity.
      */
-    public abstract @FloatRange(from = -1.0f, to = 1.0f) float getCapacity();
+    @FloatRange(from = -1.0f, to = 1.0f)
+    public abstract float getCapacity();
 }
diff --git a/core/java/android/hardware/DataSpace.java b/core/java/android/hardware/DataSpace.java
index 01ed132..6c42776 100644
--- a/core/java/android/hardware/DataSpace.java
+++ b/core/java/android/hardware/DataSpace.java
@@ -410,6 +410,22 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, value = {
+        DATASPACE_HEIF,
+    })
+    public @interface DataSpaceFileFormat {};
+
+    /**
+     * High Efficiency Image File Format (HEIF).
+     *
+     * <p>This value is valid with {@link android.hardware.HardwareBuffer#BLOB HardwareBuffer.BLOB}
+     * format. The combination is an HEIC image encoded by HEIC or HEVC encoder according to
+     * ISO/IEC 23008-12.</p>
+     */
+    public static final int DATASPACE_HEIF = 4100;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
         DATASPACE_UNKNOWN,
         DATASPACE_SCRGB_LINEAR,
         DATASPACE_SRGB,
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 18d86d6..1c4898a 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -882,6 +882,7 @@
             }
 
             // Indicate if the discontinuity count changed
+            t.firstEventAfterDiscontinuity = false;
             if (t.sensor.getType() == Sensor.TYPE_HEAD_TRACKER) {
                 final int lastCount = mSensorDiscontinuityCounts.get(handle);
                 final int curCount = Float.floatToIntBits(values[6]);
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 98f571b..c59d757 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -217,7 +217,8 @@
             FINGERPRINT_ACQUIRED_START,
             FINGERPRINT_ACQUIRED_UNKNOWN,
             FINGERPRINT_ACQUIRED_IMMOBILE,
-            FINGERPRINT_ACQUIRED_TOO_BRIGHT})
+            FINGERPRINT_ACQUIRED_TOO_BRIGHT,
+            FINGERPRINT_ACQUIRED_POWER_PRESSED})
     @Retention(RetentionPolicy.SOURCE)
     @interface FingerprintAcquired {}
 
@@ -302,6 +303,13 @@
     int FINGERPRINT_ACQUIRED_TOO_BRIGHT = 10;
 
     /**
+     * For sensors that have the power button co-located with their sensor, this event will
+     * be sent during enrollment.
+     * @hide
+     */
+    int FINGERPRINT_ACQUIRED_POWER_PRESSED = 11;
+
+    /**
      * @hide
      */
     int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 52cef0f..d57a272 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -28,9 +28,9 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.window.DisplayWindowPolicyController;
+import android.window.ScreenCapture;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -118,7 +118,7 @@
      * @param displayId The display id to take the screenshot of.
      * @return The buffer or null if we have failed.
      */
-    public abstract SurfaceControl.ScreenshotHardwareBuffer systemScreenshot(int displayId);
+    public abstract ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId);
 
     /**
      * General screenshot functionality that excludes secure layers and applies appropriate
@@ -127,7 +127,7 @@
      * @param displayId The display id to take the screenshot of.
      * @return The buffer or null if we have failed.
      */
-    public abstract SurfaceControl.ScreenshotHardwareBuffer userScreenshot(int displayId);
+    public abstract ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId);
 
     /**
      * Returns information about the specified logical display.
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index ca3e580..fa3c450 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -184,4 +184,9 @@
 
     // Query for DISPLAY_DECORATION support.
     DisplayDecorationSupport getDisplayDecorationSupport(int displayId);
+
+    // This method is to support behavior that was calling hidden APIs. The caller was requesting
+    // to set the layerStack after the display was created, which is not something we support in
+    // DMS. This should be deleted in V release.
+    void setDisplayIdToMirror(in IBinder token, int displayId);
 }
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 71cbd20..02ab8be 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -68,6 +68,13 @@
     }
 
     /**
+     * @hide
+     */
+    public IVirtualDisplayCallback getToken() {
+        return mToken;
+    }
+
+    /**
      * Sets the surface that backs the virtual display.
      * <p>
      * Detaching the surface that backs a virtual display has a similar effect to
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 72d8122..0fd164d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1538,6 +1538,9 @@
             case FINGERPRINT_ACQUIRED_TOO_BRIGHT:
                 return context.getString(
                    com.android.internal.R.string.fingerprint_acquired_too_bright);
+            case FINGERPRINT_ACQUIRED_POWER_PRESSED:
+                return context.getString(
+                        com.android.internal.R.string.fingerprint_acquired_power_press);
             case FINGERPRINT_ACQUIRED_VENDOR: {
                 String[] msgArray = context.getResources().getStringArray(
                         com.android.internal.R.array.fingerprint_acquired_vendor);
diff --git a/core/java/android/hardware/input/IInputDeviceBatteryListener.aidl b/core/java/android/hardware/input/IInputDeviceBatteryListener.aidl
new file mode 100644
index 0000000..dc5a966
--- /dev/null
+++ b/core/java/android/hardware/input/IInputDeviceBatteryListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+/** @hide */
+oneway interface IInputDeviceBatteryListener {
+
+    /**
+     * Called when there is a change in battery state for a monitored device. This will be called
+     * immediately after the listener is successfully registered for a new device via IInputManager.
+     * The parameters are values exposed through {@link android.hardware.BatteryState}.
+     */
+    void onBatteryStateChanged(int deviceId, boolean isBatteryPresent, int status, float capacity,
+            long eventTime);
+}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index c9a096c..36297b9 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -20,6 +20,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.IInputDevicesChangedListener;
+import android.hardware.input.IInputDeviceBatteryListener;
 import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.TouchCalibration;
 import android.os.CombinedVibration;
@@ -157,4 +158,8 @@
     void closeLightSession(int deviceId, in IBinder token);
 
     void cancelCurrentTouch();
+
+    void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener);
+
+    void unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 6ad1c72..8960d2a 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -30,6 +30,7 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.hardware.BatteryState;
 import android.hardware.SensorManager;
 import android.hardware.lights.Light;
 import android.hardware.lights.LightState;
@@ -65,6 +66,7 @@
 import android.view.VerifiedInputEvent;
 import android.view.WindowManager.LayoutParams;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 
@@ -72,6 +74,8 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * Provides information about input devices and available key layouts.
@@ -103,6 +107,14 @@
     private TabletModeChangedListener mTabletModeChangedListener;
     private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
 
+    private final Object mBatteryListenersLock = new Object();
+    // Maps a deviceId whose battery is currently being monitored to an entry containing the
+    // registered listeners for that device.
+    @GuardedBy("mBatteryListenersLock")
+    private SparseArray<RegisteredBatteryListeners> mBatteryListeners;
+    @GuardedBy("mBatteryListenersLock")
+    private IInputDeviceBatteryListener mInputDeviceBatteryListener;
+
     private InputDeviceSensorManager mInputDeviceSensorManager;
     /**
      * Broadcast Action: Query available keyboard layouts.
@@ -1707,6 +1719,129 @@
     }
 
     /**
+     * Adds a battery listener to be notified about {@link BatteryState} changes for an input
+     * device. The same listener can be registered for multiple input devices.
+     * The listener will be notified of the initial battery state of the device after it is
+     * successfully registered.
+     * @param deviceId the input device that should be monitored
+     * @param executor an executor on which the callback will be called
+     * @param listener the {@link InputDeviceBatteryListener}
+     * @see #removeInputDeviceBatteryListener(int, InputDeviceBatteryListener)
+     * @hide
+     */
+    public void addInputDeviceBatteryListener(int deviceId, @NonNull Executor executor,
+            @NonNull InputDeviceBatteryListener listener) {
+        Objects.requireNonNull(executor, "executor should not be null");
+        Objects.requireNonNull(listener, "listener should not be null");
+
+        synchronized (mBatteryListenersLock) {
+            if (mBatteryListeners == null) {
+                mBatteryListeners = new SparseArray<>();
+                mInputDeviceBatteryListener = new LocalInputDeviceBatteryListener();
+            }
+            RegisteredBatteryListeners listenersForDevice = mBatteryListeners.get(deviceId);
+            if (listenersForDevice == null) {
+                // The deviceId is currently not being monitored for battery changes.
+                // Start monitoring the device.
+                listenersForDevice = new RegisteredBatteryListeners();
+                mBatteryListeners.put(deviceId, listenersForDevice);
+                try {
+                    mIm.registerBatteryListener(deviceId, mInputDeviceBatteryListener);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            } else {
+                // The deviceId is already being monitored for battery changes.
+                // Ensure that the listener is not already registered.
+                for (InputDeviceBatteryListenerDelegate delegate : listenersForDevice.mDelegates) {
+                    if (Objects.equals(listener, delegate.mListener)) {
+                        throw new IllegalArgumentException(
+                                "Attempting to register an InputDeviceBatteryListener that has "
+                                        + "already been registered for deviceId: "
+                                        + deviceId);
+                    }
+                }
+            }
+            final InputDeviceBatteryListenerDelegate delegate =
+                    new InputDeviceBatteryListenerDelegate(listener, executor);
+            listenersForDevice.mDelegates.add(delegate);
+
+            // Notify the listener immediately if we already have the latest battery state.
+            if (listenersForDevice.mLatestBatteryState != null) {
+                delegate.notifyBatteryStateChanged(listenersForDevice.mLatestBatteryState);
+            }
+        }
+    }
+
+    /**
+     * Removes a previously registered battery listener for an input device.
+     * @see #addInputDeviceBatteryListener(int, Executor, InputDeviceBatteryListener)
+     * @hide
+     */
+    public void removeInputDeviceBatteryListener(int deviceId,
+            @NonNull InputDeviceBatteryListener listener) {
+        Objects.requireNonNull(listener, "listener should not be null");
+
+        synchronized (mBatteryListenersLock) {
+            if (mBatteryListeners == null) {
+                return;
+            }
+            RegisteredBatteryListeners listenersForDevice = mBatteryListeners.get(deviceId);
+            if (listenersForDevice == null) {
+                // The deviceId is not currently being monitored.
+                return;
+            }
+            final List<InputDeviceBatteryListenerDelegate> delegates =
+                    listenersForDevice.mDelegates;
+            for (int i = 0; i < delegates.size();) {
+                if (Objects.equals(listener, delegates.get(i).mListener)) {
+                    delegates.remove(i);
+                    continue;
+                }
+                i++;
+            }
+            if (!delegates.isEmpty()) {
+                return;
+            }
+
+            // There are no more battery listeners for this deviceId. Stop monitoring this device.
+            mBatteryListeners.remove(deviceId);
+            try {
+                mIm.unregisterBatteryListener(deviceId, mInputDeviceBatteryListener);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            if (mBatteryListeners.size() == 0) {
+                // There are no more devices being monitored, so the registered
+                // IInputDeviceBatteryListener will be automatically dropped by the server.
+                mBatteryListeners = null;
+                mInputDeviceBatteryListener = null;
+            }
+        }
+    }
+
+    /**
+     * 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.
+     * @see InputDevice#getBatteryState()
+     * @see #addInputDeviceBatteryListener(int, Executor, InputDeviceBatteryListener)
+     * @see #removeInputDeviceBatteryListener(int, InputDeviceBatteryListener)
+     * @hide
+     */
+    public interface InputDeviceBatteryListener {
+        /**
+         * Called when the battery state of an input device changes.
+         * @param deviceId the input device for which the battery changed.
+         * @param eventTimeMillis the time (in ms) when the battery change took place.
+         *        This timestamp is in the {@link SystemClock#uptimeMillis()} time base.
+         * @param batteryState the new battery state, never null.
+         */
+        void onBatteryStateChanged(
+                int deviceId, long eventTimeMillis, @NonNull BatteryState batteryState);
+    }
+
+    /**
      * Listens for changes in input devices.
      */
     public interface InputDeviceListener {
@@ -1816,4 +1951,76 @@
             }
         }
     }
+
+    private static final class LocalBatteryState extends BatteryState {
+        final int mDeviceId;
+        final boolean mIsPresent;
+        final int mStatus;
+        final float mCapacity;
+        final long mEventTime;
+
+        LocalBatteryState(int deviceId, boolean isPresent, int status, float capacity,
+                long eventTime) {
+            mDeviceId = deviceId;
+            mIsPresent = isPresent;
+            mStatus = status;
+            mCapacity = capacity;
+            mEventTime = eventTime;
+        }
+
+        @Override
+        public boolean isPresent() {
+            return mIsPresent;
+        }
+
+        @Override
+        public int getStatus() {
+            return mStatus;
+        }
+
+        @Override
+        public float getCapacity() {
+            return mCapacity;
+        }
+    }
+
+    private static final class RegisteredBatteryListeners {
+        final List<InputDeviceBatteryListenerDelegate> mDelegates = new ArrayList<>();
+        LocalBatteryState mLatestBatteryState;
+    }
+
+    private static final class InputDeviceBatteryListenerDelegate {
+        final InputDeviceBatteryListener mListener;
+        final Executor mExecutor;
+
+        InputDeviceBatteryListenerDelegate(InputDeviceBatteryListener listener, Executor executor) {
+            mListener = listener;
+            mExecutor = executor;
+        }
+
+        void notifyBatteryStateChanged(LocalBatteryState batteryState) {
+            mExecutor.execute(() ->
+                    mListener.onBatteryStateChanged(batteryState.mDeviceId, batteryState.mEventTime,
+                            batteryState));
+        }
+    }
+
+    private class LocalInputDeviceBatteryListener extends IInputDeviceBatteryListener.Stub {
+        @Override
+        public void onBatteryStateChanged(int deviceId, boolean isBatteryPresent, int status,
+                float capacity, long eventTime) {
+            synchronized (mBatteryListenersLock) {
+                if (mBatteryListeners == null) return;
+                final RegisteredBatteryListeners entry = mBatteryListeners.get(deviceId);
+                if (entry == null) return;
+
+                entry.mLatestBatteryState =
+                        new LocalBatteryState(
+                                deviceId, isBatteryPresent, status, capacity, eventTime);
+                for (InputDeviceBatteryListenerDelegate delegate : entry.mDelegates) {
+                    delegate.notifyBatteryStateChanged(entry.mLatestBatteryState);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
index 84c3623..6f758de 100644
--- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
+++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
@@ -27,13 +27,17 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.DeleteGesture;
+import android.view.inputmethod.DeleteRangeGesture;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.HandwritingGesture;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
+import android.view.inputmethod.SelectRangeGesture;
 import android.view.inputmethod.SurroundingText;
 import android.view.inputmethod.TextAttribute;
 
@@ -633,16 +637,13 @@
     }
 
     /**
-     * Invokes one of {@link IRemoteInputConnection#performHandwritingSelectGesture(
-     * InputConnectionCommandHeader, SelectGesture, AndroidFuture)},
-     * {@link IRemoteInputConnection#performHandwritingDeleteGesture(InputConnectionCommandHeader,
-     * DeleteGesture, AndroidFuture)},
-     * {@link IRemoteInputConnection#performHandwritingInsertGesture(InputConnectionCommandHeader,
-     * InsertGesture, AndroidFuture)}
-     *
-     * @param {@code gesture} parameter {@link HandwritingGesture}.
-     * @return {@link AndroidFuture<Integer>} that can be used to retrieve the invocation
-     *         result. {@link RemoteException} will be treated as an error.
+     * Invokes one of {@link IRemoteInputConnection#performHandwritingSelectGesture},
+     * {@link IRemoteInputConnection#performHandwritingSelectRangeGesture},
+     * {@link IRemoteInputConnection#performHandwritingDeleteGesture},
+     * {@link IRemoteInputConnection#performHandwritingDeleteRangeGesture},
+     * {@link IRemoteInputConnection#performHandwritingInsertGesture},
+     * {@link IRemoteInputConnection#performHandwritingRemoveSpaceGesture},
+     * {@link IRemoteInputConnection#performHandwritingJoinOrSplitGesture}.
      */
     @AnyThread
     public void performHandwritingGesture(
@@ -658,12 +659,24 @@
             if (gesture instanceof SelectGesture) {
                 mConnection.performHandwritingSelectGesture(
                         createHeader(), (SelectGesture) gesture, resultReceiver);
+            } else if (gesture instanceof SelectRangeGesture) {
+                mConnection.performHandwritingSelectRangeGesture(
+                        createHeader(), (SelectRangeGesture) gesture, resultReceiver);
             } else if (gesture instanceof InsertGesture) {
                 mConnection.performHandwritingInsertGesture(
                         createHeader(), (InsertGesture) gesture, resultReceiver);
             } else if (gesture instanceof DeleteGesture) {
                 mConnection.performHandwritingDeleteGesture(
                         createHeader(), (DeleteGesture) gesture, resultReceiver);
+            } else if (gesture instanceof DeleteRangeGesture) {
+                mConnection.performHandwritingDeleteRangeGesture(
+                        createHeader(), (DeleteRangeGesture) gesture, resultReceiver);
+            } else if (gesture instanceof RemoveSpaceGesture) {
+                mConnection.performHandwritingRemoveSpaceGesture(
+                        createHeader(), (RemoveSpaceGesture) gesture, resultReceiver);
+            } else if (gesture instanceof JoinOrSplitGesture) {
+                mConnection.performHandwritingJoinOrSplitGesture(
+                        createHeader(), (JoinOrSplitGesture) gesture, resultReceiver);
             } else if (consumer != null && executor != null) {
                 executor.execute(()
                         -> consumer.accept(InputConnection.HANDWRITING_GESTURE_RESULT_UNSUPPORTED));
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 87579eb..4e3adfb 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -27,6 +27,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -396,6 +397,20 @@
     final <T> T getValueAt(int i, @Nullable Class<T> clazz, @Nullable Class<?>... itemTypes) {
         Object object = mMap.valueAt(i);
         if (object instanceof BiFunction<?, ?, ?>) {
+            synchronized (this) {
+                object = unwrapLazyValueFromMapLocked(i, clazz, itemTypes);
+            }
+        }
+        return (clazz != null) ? clazz.cast(object) : (T) object;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Nullable
+    @GuardedBy("this")
+    private Object unwrapLazyValueFromMapLocked(int i, @Nullable Class<?> clazz,
+            @Nullable Class<?>... itemTypes) {
+        Object object = mMap.valueAt(i);
+        if (object instanceof BiFunction<?, ?, ?>) {
             try {
                 object = ((BiFunction<Class<?>, Class<?>[], ?>) object).apply(clazz, itemTypes);
             } catch (BadParcelableException e) {
@@ -409,7 +424,8 @@
             mMap.setValueAt(i, object);
             mLazyValues--;
             if (mOwnsLazyValues) {
-                Preconditions.checkState(mLazyValues >= 0, "Lazy values ref count below 0");
+                Preconditions.checkState(mLazyValues >= 0,
+                        "Lazy values ref count below 0");
                 // No more lazy values in mMap, so we can recycle the parcel early rather than
                 // waiting for the next GC run
                 if (mLazyValues == 0) {
@@ -420,7 +436,7 @@
                 }
             }
         }
-        return (clazz != null) ? clazz.cast(object) : (T) object;
+        return object;
     }
 
     private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean ownsParcel,
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 0ad596b..d71b023 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -961,7 +961,7 @@
          * also be bumped.
          */
         static final String[] USER_ACTIVITY_TYPES = {
-            "other", "button", "touch", "accessibility", "attention"
+            "other", "button", "touch", "accessibility", "attention", "faceDown", "deviceState"
         };
 
         public static final int NUM_USER_ACTIVITY_TYPES = USER_ACTIVITY_TYPES.length;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 7105b1a..0c5f778 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -33,6 +33,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.Closeable;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -448,6 +449,16 @@
         return proto.getBytes();
     }
 
+    /**
+     * Writes contents in a binary protobuffer format, using
+     * the android.os.BatteryUsageStatsAtomsProto proto.
+     */
+    public void dumpToProto(FileDescriptor fd) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+        writeStatsProto(proto, /* max size */ Integer.MAX_VALUE);
+        proto.flush();
+    }
+
     @NonNull
     private void writeStatsProto(ProtoOutputStream proto, int maxRawSize) {
         final AggregateBatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 80cf2f8..d2e5f9e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -22,7 +22,6 @@
 import android.app.AppOpsManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ExceptionUtils;
-import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 
@@ -144,9 +143,6 @@
      */
     private static volatile boolean sStackTrackingEnabled = false;
 
-    private static final Object sTracingUidsWriteLock = new Object();
-    private static volatile IntArray sTracingUidsImmutable = new IntArray();
-
     /**
      * Enable Binder IPC stack tracking. If enabled, every binder transaction will be logged to
      * {@link TransactionTracker}.
@@ -167,17 +163,6 @@
     }
 
     /**
-     * @hide
-     */
-    public static void enableTracingForUid(int uid) {
-        synchronized (sTracingUidsWriteLock) {
-            final IntArray copy = sTracingUidsImmutable.clone();
-            copy.add(uid);
-            sTracingUidsImmutable = copy;
-        }
-    }
-
-    /**
      * Check if binder transaction stack tracking is enabled.
      *
      * @hide
@@ -187,13 +172,6 @@
     }
 
     /**
-     * @hide
-     */
-    public static boolean isTracingEnabled(int callingUid) {
-        return sTracingUidsImmutable.indexOf(callingUid) != -1;
-    }
-
-    /**
      * Get the binder transaction tracker for this process.
      *
      * @hide
@@ -1262,8 +1240,15 @@
         // Log any exceptions as warnings, don't silently suppress them.
         // If the call was {@link IBinder#FLAG_ONEWAY} then these exceptions
         // disappear into the ether.
-        final boolean tracingEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL) &&
-                (Binder.isStackTrackingEnabled() || Binder.isTracingEnabled(callingUid));
+        final boolean tagEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_AIDL);
+        final String transactionTraceName;
+        if (tagEnabled) {
+            transactionTraceName = getTransactionTraceName(code);
+        } else {
+            transactionTraceName = null;
+        }
+
+        final boolean tracingEnabled = tagEnabled && transactionTraceName != null;
         try {
             final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
             if (heavyHitterWatcher != null) {
@@ -1271,7 +1256,7 @@
                 heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
             }
             if (tracingEnabled) {
-                Trace.traceBegin(Trace.TRACE_TAG_AIDL, getTransactionTraceName(code));
+                Trace.traceBegin(Trace.TRACE_TAG_AIDL, transactionTraceName);
             }
 
             if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 01b75d1..c0e2864 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -348,6 +348,39 @@
     public static final int USER_ACTIVITY_EVENT_DEVICE_STATE = 6;
 
     /**
+     * @hide
+     */
+    @IntDef(prefix = { "USER_ACTIVITY_EVENT_" }, value = {
+            USER_ACTIVITY_EVENT_OTHER,
+            USER_ACTIVITY_EVENT_BUTTON,
+            USER_ACTIVITY_EVENT_TOUCH,
+            USER_ACTIVITY_EVENT_ACCESSIBILITY,
+            USER_ACTIVITY_EVENT_ATTENTION,
+            USER_ACTIVITY_EVENT_FACE_DOWN,
+            USER_ACTIVITY_EVENT_DEVICE_STATE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UserActivityEvent{}
+
+    /**
+     *
+     * Convert the user activity event to a string for debugging purposes.
+     * @hide
+     */
+    public static String userActivityEventToString(@UserActivityEvent int userActivityEvent) {
+        switch (userActivityEvent) {
+            case USER_ACTIVITY_EVENT_OTHER: return "other";
+            case USER_ACTIVITY_EVENT_BUTTON: return "button";
+            case USER_ACTIVITY_EVENT_TOUCH: return "touch";
+            case USER_ACTIVITY_EVENT_ACCESSIBILITY: return "accessibility";
+            case USER_ACTIVITY_EVENT_ATTENTION: return "attention";
+            case USER_ACTIVITY_EVENT_FACE_DOWN: return "faceDown";
+            case USER_ACTIVITY_EVENT_DEVICE_STATE: return "deviceState";
+            default: return Integer.toString(userActivityEvent);
+        }
+    }
+
+    /**
      * User activity flag: If already dimmed, extend the dim timeout
      * but do not brighten.  This flag is useful for keeping the screen on
      * a little longer without causing a visible change such as when
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 237f6ed..71bc4b3 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1077,13 +1077,13 @@
         }
 
         /**
-         * Compose all of the added primitives together into a single {@link VibrationEffect}.
+         * Compose all of the added elements together into a single {@link VibrationEffect}.
          *
          * <p>The {@link Composition} object is still valid after this call, so you can continue
-         * adding more primitives to it and generating more {@link VibrationEffect}s by calling this
+         * adding more elements to it and generating more {@link VibrationEffect}s by calling this
          * method again.
          *
-         * @return The {@link VibrationEffect} resulting from the composition of the primitives.
+         * @return The {@link VibrationEffect} resulting from the composition of the elements.
          */
         @NonNull
         public VibrationEffect compose() {
diff --git a/core/java/android/os/logcat/OWNERS b/core/java/android/os/logcat/OWNERS
index cb21a6f..9f14eba 100644
--- a/core/java/android/os/logcat/OWNERS
+++ b/core/java/android/os/logcat/OWNERS
@@ -1 +1 @@
-include platform/frameworks/base:/services/core/java/com/android/server/logcat/OWNERS
+file:platform/frameworks/base:/services/core/java/com/android/server/logcat/OWNERS
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 0a6a405..2c0be87 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -541,7 +541,8 @@
         }
 
         public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
-            obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
+            obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, Boolean.valueOf(mute))
+                    .sendToTarget();
         }
     }
 
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index b7adcb8..fe46c9e 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -775,6 +775,22 @@
      */
     public static final String NAMESPACE_WEAR = "wear";
 
+    /**
+     * Namespace for the input method manager platform features.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager";
+
+    /**
+     * Namespace for backup and restore service related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_BACKUP_AND_RESTORE = "backup_and_restore";
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/InputMethodManagerDeviceConfig.java b/core/java/android/provider/InputMethodManagerDeviceConfig.java
new file mode 100644
index 0000000..906b133
--- /dev/null
+++ b/core/java/android/provider/InputMethodManagerDeviceConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.TestApi;
+
+/**
+ * Interface for accessing keys belonging to {@link DeviceConfig#NAMESPACE_INPUT_METHOD_MANAGER}.
+ * @hide
+ */
+@TestApi
+public interface InputMethodManagerDeviceConfig {
+    /**
+     * Whether the IME should be hidden when the window gained focus without an editor focused.
+     */
+    String KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS = "hide_ime_when_no_editor_focus";
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 14598d5..a99d0f0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6695,6 +6695,26 @@
         public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
 
         /**
+         * This is used by LocalBluetoothLeBroadcast to store the broadcast program info.
+         * @hide
+         */
+        public static final String BLUETOOTH_LE_BROADCAST_PROGRAM_INFO =
+                "bluetooth_le_broadcast_program_info";
+
+        /**
+         * This is used by LocalBluetoothLeBroadcast to store the broadcast code.
+         * @hide
+         */
+        public static final String BLUETOOTH_LE_BROADCAST_CODE = "bluetooth_le_broadcast_code";
+
+        /**
+         * This is used by LocalBluetoothLeBroadcast to store the app source name.
+         * @hide
+         */
+        public static final String BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME =
+                "bluetooth_le_broadcast_app_source_name";
+
+        /**
          * Setting to indicate that on device captions are enabled.
          *
          * @hide
diff --git a/core/java/android/security/keymaster/OWNERS b/core/java/android/security/keymaster/OWNERS
index 65129a4..c4d605c 100644
--- a/core/java/android/security/keymaster/OWNERS
+++ b/core/java/android/security/keymaster/OWNERS
@@ -1,5 +1,5 @@
 # Bug component: 189335
 
 swillden@google.com
-jdanis@google.com
+eranm@google.com
 jbires@google.com
diff --git a/core/java/android/service/games/TEST_MAPPING b/core/java/android/service/games/TEST_MAPPING
new file mode 100644
index 0000000..3e551ef
--- /dev/null
+++ b/core/java/android/service/games/TEST_MAPPING
@@ -0,0 +1,16 @@
+{
+  "presubmit": [
+    // TODO(b/245615658): fix flaky CTS test CtsGameServiceTestCases and add it as presubmit
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {
+          "include-filter": "android.service.games"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 267b2ff..4d33bfd 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -91,6 +91,12 @@
     public final int icon;
 
     /**
+     * The maximum string length for any string contained in this condition.
+     * @hide
+     */
+    public static final int MAX_STRING_LENGTH = 1000;
+
+    /**
      * An object representing the current state of a {@link android.app.AutomaticZenRule}.
      * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule
      * @param summary a user visible description of the rule state.
@@ -104,16 +110,19 @@
         if (id == null) throw new IllegalArgumentException("id is required");
         if (summary == null) throw new IllegalArgumentException("summary is required");
         if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
-        this.id = id;
-        this.summary = summary;
-        this.line1 = line1;
-        this.line2 = line2;
+        this.id = getTrimmedUri(id);
+        this.summary = getTrimmedString(summary);
+        this.line1 = getTrimmedString(line1);
+        this.line2 = getTrimmedString(line2);
         this.icon = icon;
         this.state = state;
         this.flags = flags;
     }
 
     public Condition(Parcel source) {
+        // This constructor passes all fields directly into the constructor that takes all the
+        // fields as arguments; that constructor will trim each of the input strings to
+        // max length if necessary.
         this((Uri)source.readParcelable(Condition.class.getClassLoader(), android.net.Uri.class),
                 source.readString(),
                 source.readString(),
@@ -240,4 +249,25 @@
             return new Condition[size];
         }
     };
+
+    /**
+     * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
+     */
+    private static String getTrimmedString(String input) {
+        if (input != null && input.length() > MAX_STRING_LENGTH) {
+            return input.substring(0, MAX_STRING_LENGTH);
+        }
+        return input;
+    }
+
+    /**
+     * Returns a truncated copy of the Uri by trimming the string representation to the maximum
+     * string length.
+     */
+    private static Uri getTrimmedUri(Uri input) {
+        if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
+            return Uri.parse(getTrimmedString(input.toString()));
+        }
+        return input;
+    }
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index ad4f9f7..684d566 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -141,7 +141,9 @@
      *
      * Without this flag, the message passed to {@code grantTrust} is only used for debugging
      * purposes. With the flag, it may be displayed to the user as the reason why the device is
-     * unlocked.
+     * unlocked. If this flag isn't set OR the message is set to null, the device will display
+     * its own default message for trust granted. If the TrustAgent intentionally doesn't want to
+     * show any message, then it can set this flag AND set the message to an empty string.
      */
     public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 1 << 3;
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index bc8822c..e4c26e0 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -93,6 +93,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.window.ClientWindowFrames;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.HandlerCaller;
@@ -518,7 +519,7 @@
          * {@link #addLocalColorsAreas(List)}
          * {@link #removeLocalColorsAreas(List)}
          * When local colors change, call {@link #notifyLocalColorsChanged(List, List)}
-         * See {@link com.android.systemui.ImageWallpaper} for an example
+         * See {@link com.android.systemui.wallpapers.ImageWallpaper} for an example
          * @hide
          */
         public boolean supportsLocalColorExtraction() {
@@ -1989,9 +1990,9 @@
                 cleanUpScreenshotSurfaceControl();
             }
 
-            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                    SurfaceControl.captureLayers(
-                            new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+            ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                    ScreenCapture.captureLayers(
+                            new ScreenCapture.LayerCaptureArgs.Builder(mSurfaceControl)
                                     // Needed because SurfaceFlinger#validateScreenshotPermissions
                                     // uses this parameter to check whether a caller only attempts
                                     // to screenshot itself when call doesn't come from the system.
diff --git a/core/java/android/text/style/SpanUtils.java b/core/java/android/text/style/SpanUtils.java
new file mode 100644
index 0000000..6b4bd1a
--- /dev/null
+++ b/core/java/android/text/style/SpanUtils.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.style;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.graphics.Typeface;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.util.LongArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class SpanUtils {
+    private SpanUtils() {}  // Do not instantiate
+
+    /**
+     * Toggle the bold state of the given range.
+     *
+     * If there is at least one character is not bold in the given range, make the entire region to
+     * be bold. If all characters of the given range is already bolded, this method removes bold
+     * style from the given selection.
+     *
+     * @param spannable a spannable string
+     * @param min minimum inclusive index of the selection.
+     * @param max maximum exclusive index of the selection.
+     * @return true if the selected region is toggled.
+     */
+    public static boolean toggleBold(@NonNull Spannable spannable,
+            @IntRange(from = 0) int min, @IntRange(from = 0) int max) {
+
+        if (min == max) {
+            return false;
+        }
+
+        final StyleSpan[] boldSpans = spannable.getSpans(min, max, StyleSpan.class);
+        final ArrayList<StyleSpan> filteredBoldSpans = new ArrayList<>();
+        for (StyleSpan span : boldSpans) {
+            if ((span.getStyle() & Typeface.BOLD) == Typeface.BOLD) {
+                filteredBoldSpans.add(span);
+            }
+        }
+
+        if (!isCovered(spannable, filteredBoldSpans, min, max)) {
+            // At least one character doesn't have bold style. Making given region bold.
+            spannable.setSpan(
+                    new StyleSpan(Typeface.BOLD), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+            return true;
+        }
+
+        // Span covers the entire selection. Removing spans from tha region.
+        for (int si = 0; si < filteredBoldSpans.size(); ++si) {
+            final StyleSpan span = filteredBoldSpans.get(si);
+            final int start = spannable.getSpanStart(span);
+            final int end = spannable.getSpanEnd(span);
+            final int flag = spannable.getSpanFlags(span);
+
+            // If BOLD_ITALIC style is attached, need to set ITALIC span to the subtracted range.
+            final boolean needItalicSpan = (span.getStyle() & Typeface.ITALIC) == Typeface.ITALIC;
+
+            if (start < min) {
+                if (end > max) {
+                    // selection: ------------|===================|----------------
+                    //      span:     <-------------------------------->
+                    //    result:     <------->                   <---->
+                    spannable.setSpan(span, start, min, flag);
+                    spannable.setSpan(new StyleSpan(span.getStyle()), max, end, flag);
+                    if (needItalicSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.ITALIC), min, max, flag);
+                    }
+                } else {
+                    // selection: ------------|===================|----------------
+                    //      span:     <----------->
+                    //    result:     <------->
+                    spannable.setSpan(span, start, min, flag);
+                    if (needItalicSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.ITALIC), min, end, flag);
+                    }
+                }
+            } else {
+                if (end > max) {
+                    // selection: ------------|===================|----------------
+                    //      span:                     <------------------------>
+                    //    result:                                 <------------>
+                    spannable.setSpan(span, max, end, flag);
+                    if (needItalicSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.ITALIC), max, end, flag);
+                    }
+                } else {
+                    // selection: ------------|===================|----------------
+                    //      span:                 <----------->
+                    //    result:
+                    spannable.removeSpan(span);
+                    if (needItalicSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.ITALIC), start, end, flag);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Toggle the italic state of the given range.
+     *
+     * If there is at least one character is not italic in the given range, make the entire region
+     * to be italic. If all characters of the given range is already italic, this method removes
+     * italic style from the given selection.
+     *
+     * @param spannable a spannable string
+     * @param min minimum inclusive index of the selection.
+     * @param max maximum exclusive index of the selection.
+     * @return true if the selected region is toggled.
+     */
+    public static boolean toggleItalic(@NonNull Spannable spannable,
+            @IntRange(from = 0) int min, @IntRange(from = 0) int max) {
+
+        if (min == max) {
+            return false;
+        }
+
+        final StyleSpan[] boldSpans = spannable.getSpans(min, max, StyleSpan.class);
+        final ArrayList<StyleSpan> filteredBoldSpans = new ArrayList<>();
+        for (StyleSpan span : boldSpans) {
+            if ((span.getStyle() & Typeface.ITALIC) == Typeface.ITALIC) {
+                filteredBoldSpans.add(span);
+            }
+        }
+
+        if (!isCovered(spannable, filteredBoldSpans, min, max)) {
+            // At least one character doesn't have italic style. Making given region italic.
+            spannable.setSpan(
+                    new StyleSpan(Typeface.ITALIC), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+            return true;
+        }
+
+        // Span covers the entire selection. Removing spans from tha region.
+        for (int si = 0; si < filteredBoldSpans.size(); ++si) {
+            final StyleSpan span = filteredBoldSpans.get(si);
+            final int start = spannable.getSpanStart(span);
+            final int end = spannable.getSpanEnd(span);
+            final int flag = spannable.getSpanFlags(span);
+
+            // If BOLD_ITALIC style is attached, need to set BOLD span to the subtracted range.
+            final boolean needBoldSpan = (span.getStyle() & Typeface.BOLD) == Typeface.BOLD;
+
+            if (start < min) {
+                if (end > max) {
+                    // selection: ------------|===================|----------------
+                    //      span:     <-------------------------------->
+                    //    result:     <------->                   <---->
+                    spannable.setSpan(span, start, min, flag);
+                    spannable.setSpan(new StyleSpan(span.getStyle()), max, end, flag);
+                    if (needBoldSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.BOLD), min, max, flag);
+                    }
+                } else {
+                    // selection: ------------|===================|----------------
+                    //      span:     <----------->
+                    //    result:     <------->
+                    spannable.setSpan(span, start, min, flag);
+                    if (needBoldSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.BOLD), min, end, flag);
+                    }
+                }
+            } else {
+                if (end > max) {
+                    // selection: ------------|===================|----------------
+                    //      span:                     <------------------------>
+                    //    result:                                 <------------>
+                    spannable.setSpan(span, max, end, flag);
+                    if (needBoldSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.BOLD), max, end, flag);
+                    }
+                } else {
+                    // selection: ------------|===================|----------------
+                    //      span:                 <----------->
+                    //    result:
+                    spannable.removeSpan(span);
+                    if (needBoldSpan) {
+                        spannable.setSpan(new StyleSpan(Typeface.BOLD), start, end, flag);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Toggle the underline state of the given range.
+     *
+     * If there is at least one character is not underlined in the given range, make the entire
+     * region to underlined. If all characters of the given range is already underlined, this
+     * method removes underline from the given selection.
+     *
+     * @param spannable a spannable string
+     * @param min minimum inclusive index of the selection.
+     * @param max maximum exclusive index of the selection.
+     * @return true if the selected region is toggled.
+     */
+    public static boolean toggleUnderline(@NonNull Spannable spannable,
+            @IntRange(from = 0) int min, @IntRange(from = 0) int max) {
+
+        if (min == max) {
+            return false;
+        }
+
+        final List<UnderlineSpan> spans =
+                Arrays.asList(spannable.getSpans(min, max, UnderlineSpan.class));
+
+        if (!isCovered(spannable, spans, min, max)) {
+            // At least one character doesn't have underline style. Making given region underline.
+            spannable.setSpan(new UnderlineSpan(), min, max, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
+            return true;
+        }
+        // Span covers the entire selection. Removing spans from tha region.
+        for (int si = 0; si < spans.size(); ++si) {
+            final UnderlineSpan span = spans.get(si);
+            final int start = spannable.getSpanStart(span);
+            final int end = spannable.getSpanEnd(span);
+            final int flag = spannable.getSpanFlags(span);
+
+            if (start < min) {
+                if (end > max) {
+                    // selection: ------------|===================|----------------
+                    //      span:     <-------------------------------->
+                    //    result:     <------->                   <---->
+                    spannable.setSpan(span, start, min, flag);
+                    spannable.setSpan(new UnderlineSpan(), max, end, flag);
+                } else {
+                    // selection: ------------|===================|----------------
+                    //      span:     <----------->
+                    //    result:     <------->
+                    spannable.setSpan(span, start, min, flag);
+                }
+            } else {
+                if (end > max) {
+                    // selection: ------------|===================|----------------
+                    //      span:                     <------------------------>
+                    //    result:                                 <------------>
+                    spannable.setSpan(span, max, end, flag);
+                } else {
+                    // selection: ------------|===================|----------------
+                    //      span:                 <----------->
+                    //    result:
+                    spannable.removeSpan(span);
+                }
+            }
+        }
+        return true;
+    }
+
+    private static long pack(int from, int to) {
+        return ((long) from) << 32 | (long) to;
+    }
+
+    private static int min(long packed) {
+        return (int) (packed >> 32);
+    }
+
+    private static int max(long packed) {
+        return (int) (packed & 0xFFFFFFFFL);
+    }
+
+    private static boolean hasIntersection(int aMin, int aMax, int bMin, int bMax) {
+        return aMin < bMax && bMin < aMax;
+    }
+
+    private static long intersection(int aMin, int aMax, int bMin, int bMax) {
+        return pack(Math.max(aMin, bMin), Math.min(aMax, bMax));
+    }
+
+    private static <T> boolean isCovered(@NonNull Spannable spannable, @NonNull List<T> spans,
+            @IntRange(from = 0) int min, @IntRange(from = 0) int max) {
+
+        if (min == max) {
+            return false;
+        }
+
+        LongArray uncoveredRanges = new LongArray();
+        LongArray nextUncoveredRanges = new LongArray();
+
+        uncoveredRanges.add(pack(min, max));
+
+        for (int si = 0; si < spans.size(); ++si) {
+            final T span = spans.get(si);
+            final int start = spannable.getSpanStart(span);
+            final int end = spannable.getSpanEnd(span);
+
+            for (int i = 0; i < uncoveredRanges.size(); ++i) {
+                final long packed = uncoveredRanges.get(i);
+                final int uncoveredStart = min(packed);
+                final int uncoveredEnd = max(packed);
+
+                if (!hasIntersection(start, end, uncoveredStart, uncoveredEnd)) {
+                    // This span doesn't affect this uncovered range. Try next span.
+                    nextUncoveredRanges.add(packed);
+                } else {
+                    // This span has an intersection with uncovered range. Update the uncovered
+                    // range.
+                    long intersectionPack = intersection(start, end, uncoveredStart, uncoveredEnd);
+                    int intersectStart = min(intersectionPack);
+                    int intersectEnd = max(intersectionPack);
+
+                    // Uncovered Range           : ----------|=======================|-------------
+                    //    Intersection           :                 <---------->
+                    // Remaining uncovered ranges: ----------|=====|----------|======|-------------
+                    if (uncoveredStart != intersectStart) {
+                        // There is still uncovered area on the left.
+                        nextUncoveredRanges.add(pack(uncoveredStart, intersectStart));
+                    }
+                    if (intersectEnd != uncoveredEnd) {
+                        // There is still uncovered area on the right.
+                        nextUncoveredRanges.add(pack(intersectEnd, uncoveredEnd));
+                    }
+                }
+            }
+
+            if (nextUncoveredRanges.size() == 0) {
+                return true;
+            }
+
+            // Swap the uncoveredRanges and nextUncoveredRanges and clear the next one.
+            final LongArray tmp = nextUncoveredRanges;
+            nextUncoveredRanges = uncoveredRanges;
+            uncoveredRanges = tmp;
+            nextUncoveredRanges.clear();
+        }
+
+        return false;
+    }
+}
diff --git a/core/java/android/util/SparseArrayMap.java b/core/java/android/util/SparseArrayMap.java
index e5bb9f45..1a2c4df 100644
--- a/core/java/android/util/SparseArrayMap.java
+++ b/core/java/android/util/SparseArrayMap.java
@@ -34,14 +34,20 @@
 public class SparseArrayMap<K, V> {
     private final SparseArray<ArrayMap<K, V>> mData = new SparseArray<>();
 
-    /** Add an entry associating obj with the int-K pair. */
-    public void add(int key, @NonNull K mapKey, @Nullable V obj) {
+    /**
+     * Add an entry associating obj with the int-K pair.
+     *
+     * @return the previous value associated with key, or null if there was no mapping for key.
+     * (A null return can also indicate that the map previously associated null with key, if the
+     * implementation supports null values.)
+     */
+    public V add(int key, @NonNull K mapKey, @Nullable V obj) {
         ArrayMap<K, V> data = mData.get(key);
         if (data == null) {
             data = new ArrayMap<>();
             mData.put(key, data);
         }
-        data.put(mapKey, obj);
+        return data.put(mapKey, obj);
     }
 
     /** Remove all entries from the map. */
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index cc68ddd..91febcd 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -765,11 +765,12 @@
                 startNanos = System.nanoTime();
                 final long jitterNanos = startNanos - frameTimeNanos;
                 if (jitterNanos >= frameIntervalNanos) {
-                    long lastFrameOffset = 0;
+                    frameTimeNanos = startNanos;
                     if (frameIntervalNanos == 0) {
                         Log.i(TAG, "Vsync data empty due to timeout");
                     } else {
-                        lastFrameOffset = jitterNanos % frameIntervalNanos;
+                        long lastFrameOffset = jitterNanos % frameIntervalNanos;
+                        frameTimeNanos = frameTimeNanos - lastFrameOffset;
                         final long skippedFrames = jitterNanos / frameIntervalNanos;
                         if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                             Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
@@ -785,8 +786,7 @@
                                     + " ms in the past.");
                         }
                     }
-                    frameTimeNanos = startNanos - lastFrameOffset;
-                    frameData.updateFrameData(frameTimeNanos);
+                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                 }
 
                 if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -884,7 +884,7 @@
                     }
                     frameTimeNanos = now - lastFrameOffset;
                     mLastFrameTimeNanos = frameTimeNanos;
-                    frameData.updateFrameData(frameTimeNanos);
+                    frameData = getUpdatedFrameData(frameTimeNanos, frameData, jitterNanos);
                 }
             }
         }
@@ -998,9 +998,6 @@
 
     /** Holds data that describes one possible VSync frame event to render at. */
     public static class FrameTimeline {
-        static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline(
-                FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE);
-
         FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
             this.mVsyncId = vsyncId;
             this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
@@ -1019,11 +1016,6 @@
             return mVsyncId;
         }
 
-        /** Reset the vsync ID to invalid. */
-        void resetVsyncId() {
-            mVsyncId = FrameInfo.INVALID_VSYNC_ID;
-        }
-
         /**
          * The time in {@link System#nanoTime()} timebase which this frame is expected to be
          * presented.
@@ -1046,39 +1038,20 @@
      * information including deadline and expected present time.
      */
     public static class FrameData {
-        static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0];
-        FrameData() {
-            this.mFrameTimelines = INVALID_FRAME_TIMELINES;
-            this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE;
-        }
-
         FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
-            FrameTimeline[] frameTimelines =
-                    new FrameTimeline[vsyncEventData.frameTimelines.length];
-            for (int i = 0; i <  vsyncEventData.frameTimelines.length; i++) {
-                DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
-                        vsyncEventData.frameTimelines[i];
-                frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
-                        frameTimeline.expectedPresentTime, frameTimeline.deadline);
-            }
             this.mFrameTimeNanos = frameTimeNanos;
-            this.mFrameTimelines = frameTimelines;
-            this.mPreferredFrameTimeline =
-                    frameTimelines[vsyncEventData.preferredFrameTimelineIndex];
+            this.mFrameTimelines = convertFrameTimelines(vsyncEventData);
+            this.mPreferredFrameTimelineIndex =
+                    vsyncEventData.preferredFrameTimelineIndex;
         }
 
         private long mFrameTimeNanos;
-        private FrameTimeline[] mFrameTimelines;
-        private FrameTimeline mPreferredFrameTimeline;
+        private final FrameTimeline[] mFrameTimelines;
+        private int mPreferredFrameTimelineIndex;
 
-        void updateFrameData(long frameTimeNanos) {
+        void updateFrameData(long frameTimeNanos, int newPreferredFrameTimelineIndex) {
             mFrameTimeNanos = frameTimeNanos;
-            for (FrameTimeline ft : mFrameTimelines) {
-                // The ID is no longer valid because the frame time that was registered with the ID
-                // no longer matches.
-                // TODO(b/205721584): Ask SF for valid vsync information.
-                ft.resetVsyncId();
-            }
+            mPreferredFrameTimelineIndex = newPreferredFrameTimelineIndex;
         }
 
         /** The time in nanoseconds when the frame started being rendered. */
@@ -1096,7 +1069,7 @@
         /** The platform-preferred frame timeline. */
         @NonNull
         public FrameTimeline getPreferredFrameTimeline() {
-            return mPreferredFrameTimeline;
+            return mFrameTimelines[mPreferredFrameTimelineIndex];
         }
 
         private FrameTimeline[] convertFrameTimelines(
@@ -1114,6 +1087,38 @@
     }
 
     /**
+     * Update the frame data when the frame is late.
+     *
+     * @param jitterNanos currentTime - frameTime
+     */
+    private FrameData getUpdatedFrameData(long frameTimeNanos, FrameData frameData,
+            long jitterNanos) {
+        int newPreferredIndex = 0;
+        FrameTimeline[] frameTimelines = frameData.getFrameTimelines();
+        final long minimumDeadline =
+                frameData.getPreferredFrameTimeline().getDeadlineNanos() + jitterNanos;
+        // Look for a non-past deadline timestamp in the existing frame data. Otherwise, binder
+        // query for new frame data. Note that binder is relatively slow, O(ms), so it is
+        // only called when the existing frame data does not hold a valid frame.
+        while (newPreferredIndex < frameTimelines.length - 1
+                && frameTimelines[newPreferredIndex].getDeadlineNanos()
+                < minimumDeadline) {
+            newPreferredIndex++;
+        }
+
+        long newPreferredDeadline =
+                frameData.getFrameTimelines()[newPreferredIndex].getDeadlineNanos();
+        if (newPreferredDeadline < minimumDeadline) {
+            DisplayEventReceiver.VsyncEventData latestVsyncEventData =
+                    mDisplayEventReceiver.getLatestVsyncEventData();
+            return new FrameData(frameTimeNanos, latestVsyncEventData);
+        } else {
+            frameData.updateFrameData(frameTimeNanos, newPreferredIndex);
+            return frameData;
+        }
+    }
+
+    /**
      * Implement this interface to receive a callback to start the next frame. The callback is
      * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The
      * callback payload contains information about multiple possible frames, allowing choice of
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index f65a69a..0ba3072 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -723,9 +723,9 @@
         outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
         outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
 
-        if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
-            compatInfo.applyToDisplayMetrics(outMetrics);
-        }
+        // Apply to size if the configuration is EMPTY because the size is from real display info.
+        final boolean applyToSize = configuration != null && appBounds == null;
+        compatInfo.applyDisplayMetricsIfNeeded(outMetrics, applyToSize);
     }
 
     // For debugging purposes
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index b6b029b..bda707b 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -195,7 +195,7 @@
      * {@link #ACTION_DRAG_ENTERED} while the drag shadow is still within the View object's bounding
      * box, but not within a descendant view that can accept the data. The {@link #getX()} and
      * {@link #getY()} methods supply
-     * the X and Y position of of the drag point within the View object's bounding box.
+     * the X and Y position of the drag point within the View object's bounding box.
      * <p>
      * A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
      * ACTION_DRAG_LOCATION events.
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index f9bb880..57ba7e9 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -653,7 +653,7 @@
                 break;
 
             case MotionEvent.ACTION_MOVE:
-                if ((mCurrentDownEvent == null) || mInLongPress || mInContextClick) {
+                if (mInLongPress || mInContextClick) {
                     break;
                 }
 
@@ -736,9 +736,6 @@
                 break;
 
             case MotionEvent.ACTION_UP:
-                if (mCurrentDownEvent == null) {
-                    break;
-                }
                 mStillDown = false;
                 MotionEvent currentUpEvent = MotionEvent.obtain(ev);
                 if (mIsDoubleTapping) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 229de31..b2a26fa 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -114,6 +114,7 @@
     @UnsupportedAppUsage
     int getInitialDisplayDensity(int displayId);
     int getBaseDisplayDensity(int displayId);
+    int getDisplayIdByUniqueId(String uniqueId);
     void setForcedDisplayDensityForUser(int displayId, int density, int userId);
     void clearForcedDisplayDensityForUser(int displayId, int userId);
     void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index b48b525..a5ac948 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -181,7 +181,8 @@
         if (!view.hasImeFocus() || !view.hasWindowFocus()) {
             return;
         }
-        if (DEBUG) Log.d(TAG, "onViewFocusChanged, view=" + view + ", mServedView=" + mServedView);
+        if (DEBUG) Log.d(TAG, "onViewFocusChanged, view=" + InputMethodDebug.dumpViewInfo(view)
+                + ", mServedView=" + InputMethodDebug.dumpViewInfo(mServedView));
 
         // We don't need to track the next served view when the view lost focus here because:
         // 1) The current view focus may be cleared temporary when in touch mode, closing input
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 2a0246b..42c37fd 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -460,10 +460,8 @@
 
     /**
      * Called by native code
-     * @hide
      */
-    @VisibleForTesting
-    public InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
+    private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
             int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
             KeyCharacterMap keyCharacterMap, @InputDeviceCountryCode int countryCode,
             boolean hasVibrator, boolean hasMicrophone, boolean hasButtonUnderPad,
@@ -520,6 +518,142 @@
     }
 
     /**
+     * InputDevice builder used to create an InputDevice for tests in Java.
+     * @hide
+     */
+    @VisibleForTesting
+    public static class Builder {
+        private int mId = 0;
+        private int mGeneration = 0;
+        private int mControllerNumber = 0;
+        private String mName = "";
+        private int mVendorId = 0;
+        private int mProductId = 0;
+        private String mDescriptor = "";
+        private boolean mIsExternal = false;
+        private int mSources = 0;
+        private int mKeyboardType = 0;
+        private KeyCharacterMap mKeyCharacterMap = null;
+        private boolean mHasVibrator = false;
+        private boolean mHasMicrophone = false;
+        private boolean mHasButtonUnderPad = false;
+        private boolean mHasSensor = false;
+        private boolean mHasBattery = false;
+        @InputDeviceCountryCode
+        private int mCountryCode = InputDeviceCountryCode.INVALID;
+
+        /** @see InputDevice#getId()  */
+        public Builder setId(int id) {
+            mId = id;
+            return this;
+        }
+
+        /** @see InputDevice#getGeneration()  */
+        public Builder setGeneration(int generation) {
+            mGeneration = generation;
+            return this;
+        }
+
+        /** @see InputDevice#getControllerNumber()  */
+        public Builder setControllerNumber(int controllerNumber) {
+            mControllerNumber = controllerNumber;
+            return this;
+        }
+
+        /** @see InputDevice#getName()  */
+        public Builder setName(String name) {
+            mName = name;
+            return this;
+        }
+
+        /** @see InputDevice#getVendorId()  */
+        public Builder setVendorId(int vendorId) {
+            mVendorId = vendorId;
+            return this;
+        }
+
+        /** @see InputDevice#getProductId()  */
+        public Builder setProductId(int productId) {
+            mProductId = productId;
+            return this;
+        }
+
+        /** @see InputDevice#getDescriptor()  */
+        public Builder setDescriptor(String descriptor) {
+            mDescriptor = descriptor;
+            return this;
+        }
+
+        /** @see InputDevice#isExternal()  */
+        public Builder setExternal(boolean external) {
+            mIsExternal = external;
+            return this;
+        }
+
+        /** @see InputDevice#getSources()  */
+        public Builder setSources(int sources) {
+            mSources = sources;
+            return this;
+        }
+
+        /** @see InputDevice#getKeyboardType()  */
+        public Builder setKeyboardType(int keyboardType) {
+            mKeyboardType = keyboardType;
+            return this;
+        }
+
+        /** @see InputDevice#getKeyCharacterMap()  */
+        public Builder setKeyCharacterMap(KeyCharacterMap keyCharacterMap) {
+            mKeyCharacterMap = keyCharacterMap;
+            return this;
+        }
+
+        /** @see InputDevice#getVibrator()  */
+        public Builder setHasVibrator(boolean hasVibrator) {
+            mHasVibrator = hasVibrator;
+            return this;
+        }
+
+        /** @see InputDevice#hasMicrophone()  */
+        public Builder setHasMicrophone(boolean hasMicrophone) {
+            mHasMicrophone = hasMicrophone;
+            return this;
+        }
+
+        /** @see InputDevice#hasButtonUnderPad()  */
+        public Builder setHasButtonUnderPad(boolean hasButtonUnderPad) {
+            mHasButtonUnderPad = hasButtonUnderPad;
+            return this;
+        }
+
+        /** @see InputDevice#hasSensor()  */
+        public Builder setHasSensor(boolean hasSensor) {
+            mHasSensor = hasSensor;
+            return this;
+        }
+
+        /** @see InputDevice#hasBattery()  */
+        public Builder setHasBattery(boolean hasBattery) {
+            mHasBattery = hasBattery;
+            return this;
+        }
+
+        /** @see InputDevice#getCountryCode()  */
+        public Builder setCountryCode(@InputDeviceCountryCode int countryCode) {
+            mCountryCode = countryCode;
+            return this;
+        }
+
+        /** Build {@link InputDevice}. */
+        public InputDevice build() {
+            return new InputDevice(mId, mGeneration, mControllerNumber, mName, mVendorId,
+                    mProductId, mDescriptor, mIsExternal, mSources, mKeyboardType, mKeyCharacterMap,
+                    mCountryCode, mHasVibrator, mHasMicrophone, mHasButtonUnderPad, mHasSensor,
+                    mHasBattery);
+        }
+    }
+
+    /**
      * Gets information about the input device with the specified id.
      * @param id The device id.
      * @return The input device or null if not found.
@@ -938,7 +1072,8 @@
      *
      * @return The lights manager associated with the device, never null.
      */
-    public @NonNull LightsManager getLightsManager() {
+    @NonNull
+    public LightsManager getLightsManager() {
         if (mLightsManager == null) {
             mLightsManager = InputManager.getInstance().getInputDeviceLightsManager(mId);
         }
@@ -956,7 +1091,8 @@
      *
      * @return The sensor manager service associated with the device, never null.
      */
-    public @NonNull SensorManager getSensorManager() {
+    @NonNull
+    public SensorManager getSensorManager() {
         synchronized (mMotionRanges) {
             if (mSensorManager == null) {
                 mSensorManager = InputManager.getInstance().getInputDeviceSensorManager(mId);
@@ -1040,6 +1176,15 @@
     }
 
     /**
+     * Reports whether the device has a battery.
+     * @return true if the device has a battery, false otherwise.
+     * @hide
+     */
+    public boolean hasBattery() {
+        return mHasBattery;
+    }
+
+    /**
      * Provides information about the range of values for a particular {@link MotionEvent} axis.
      *
      * @see InputDevice#getMotionRange(int)
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index c3a638c..9789b56 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -866,13 +866,39 @@
     public static final int KEYCODE_DEMO_APP_3 = 303;
     /** Key code constant: Demo Application key #4. */
     public static final int KEYCODE_DEMO_APP_4 = 304;
+    /** Key code constant: Keyboard backlight down */
+    public static final int KEYCODE_KEYBOARD_BACKLIGHT_DOWN = 305;
+    /** Key code constant: Keyboard backlight up */
+    public static final int KEYCODE_KEYBOARD_BACKLIGHT_UP = 306;
+    /** Key code constant: Keyboard backlight toggle */
+    public static final int KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307;
+    /**
+     * Key code constant: The primary button on the barrel of a stylus.
+     * This is usually the button closest to the tip of the stylus.
+     */
+    public static final int KEYCODE_STYLUS_BUTTON_PRIMARY = 308;
+    /**
+     * Key code constant: The secondary button on the barrel of a stylus.
+     * This is usually the second button from the tip of the stylus.
+     */
+    public static final int KEYCODE_STYLUS_BUTTON_SECONDARY = 309;
+    /**
+     * Key code constant: The tertiary button on the barrel of a stylus.
+     * This is usually the third button from the tip of the stylus.
+     */
+    public static final int KEYCODE_STYLUS_BUTTON_TERTIARY = 310;
+    /**
+     * Key code constant: A button on the tail end of a stylus.
+     * The use of this button does not usually correspond to the function of an eraser.
+     */
+    public static final int KEYCODE_STYLUS_BUTTON_TAIL = 311;
 
    /**
      * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
      * @hide
      */
     @TestApi
-    public static final int LAST_KEYCODE = KEYCODE_DEMO_APP_4;
+    public static final int LAST_KEYCODE = KEYCODE_STYLUS_BUTTON_TAIL;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -2019,6 +2045,9 @@
             case KeyEvent.KEYCODE_SEARCH:
             case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
             case KeyEvent.KEYCODE_BRIGHTNESS_UP:
+            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
+            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
+            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
             case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
             case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index aef38eb..fb0cac3 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -22,6 +22,7 @@
 import static android.graphics.Matrix.MSKEW_Y;
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.SurfaceControlProto.HASH_CODE;
 import static android.view.SurfaceControlProto.LAYER_ID;
 import static android.view.SurfaceControlProto.NAME;
@@ -35,7 +36,7 @@
 import android.annotation.Size;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.graphics.Bitmap;
+import android.content.Context;
 import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
@@ -48,15 +49,23 @@
 import android.hardware.HardwareBuffer;
 import android.hardware.SyncFence;
 import android.hardware.display.DeviceProductInfo;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
+import android.hardware.display.IDisplayManager;
+import android.hardware.display.IVirtualDisplayCallback;
+import android.hardware.display.VirtualDisplay;
 import android.hardware.graphics.common.DisplayDecorationSupport;
+import android.media.projection.MediaProjectionGlobal;
 import android.opengl.EGLDisplay;
 import android.opengl.EGLSync;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseIntArray;
@@ -80,9 +89,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
 /**
@@ -107,10 +114,7 @@
     private static native void nativeRelease(long nativeObject);
     private static native void nativeDisconnect(long nativeObject);
     private static native void nativeUpdateDefaultBufferSize(long nativeObject, int width, int height);
-    private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
-            ScreenCaptureListener captureListener);
-    private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
-            ScreenCaptureListener captureListener);
+
     private static native long nativeMirrorSurface(long mirrorOfObject);
     private static native long nativeCreateTransaction();
     private static native long nativeGetNativeTransactionFinalizer();
@@ -172,8 +176,6 @@
 
     private static native long[] nativeGetPhysicalDisplayIds();
     private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId);
-    private static native IBinder nativeCreateDisplay(String name, boolean secure);
-    private static native void nativeDestroyDisplay(IBinder displayToken);
     private static native void nativeSetDisplaySurface(long transactionObj,
             IBinder displayToken, long nativeSurfaceObject);
     private static native void nativeSetDisplayLayerStack(long transactionObj,
@@ -521,7 +523,7 @@
      * be copied. In particular, screenshots and secondary, non-secure displays will render black
      * content instead of the surface content.
      *
-     * @see #createDisplay(String, boolean)
+     * @see com.android.server.display.DisplayControl#createDisplay(String, boolean)
      * @hide
      */
     public static final int SECURE = 0x00000080;
@@ -781,412 +783,6 @@
     public static final int METADATA_GAME_MODE = 8;
 
     /**
-     * A wrapper around HardwareBuffer that contains extra information about how to
-     * interpret the screenshot HardwareBuffer.
-     *
-     * @hide
-     */
-    public static class ScreenshotHardwareBuffer {
-        private final HardwareBuffer mHardwareBuffer;
-        private final ColorSpace mColorSpace;
-        private final boolean mContainsSecureLayers;
-        private final boolean mContainsHdrLayers;
-
-        public ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace,
-                boolean containsSecureLayers, boolean containsHdrLayers) {
-            mHardwareBuffer = hardwareBuffer;
-            mColorSpace = colorSpace;
-            mContainsSecureLayers = containsSecureLayers;
-            mContainsHdrLayers = containsHdrLayers;
-        }
-
-       /**
-        * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
-        * @param hardwareBuffer The existing HardwareBuffer object
-        * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
-        * @param containsSecureLayers Indicates whether this graphic buffer contains captured
-        *                             contents of secure layers, in which case the screenshot
-        *                             should not be persisted.
-        * @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
-        */
-        private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
-                int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
-            ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
-            return new ScreenshotHardwareBuffer(
-                    hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
-        }
-
-        public ColorSpace getColorSpace() {
-            return mColorSpace;
-        }
-
-        public HardwareBuffer getHardwareBuffer() {
-            return mHardwareBuffer;
-        }
-
-        public boolean containsSecureLayers() {
-            return mContainsSecureLayers;
-        }
-        /**
-         * Returns whether the screenshot contains at least one HDR layer.
-         * This information may be useful for informing the display whether this screenshot
-         * is allowed to be dimmed to SDR white.
-         */
-        public boolean containsHdrLayers() {
-            return mContainsHdrLayers;
-        }
-
-        /**
-         * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it.
-         * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap
-         * into
-         * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
-         *
-         * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to
-         * directly
-         * use the {@link HardwareBuffer} directly.
-         *
-         * @return Bitmap generated from the {@link HardwareBuffer}
-         */
-        public Bitmap asBitmap() {
-            if (mHardwareBuffer == null) {
-                Log.w(TAG, "Failed to take screenshot. Null screenshot object");
-                return null;
-            }
-            return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public interface ScreenCaptureListener {
-        /**
-         * The callback invoked when the screen capture is complete.
-         * @param hardwareBuffer Data containing info about the screen capture.
-         */
-        void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer);
-    }
-
-    private static class SyncScreenCaptureListener implements ScreenCaptureListener {
-        private static final int SCREENSHOT_WAIT_TIME_S = 1;
-        private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
-        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
-
-        @Override
-        public void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
-            mScreenshotHardwareBuffer = hardwareBuffer;
-            mCountDownLatch.countDown();
-        }
-
-        private ScreenshotHardwareBuffer waitForScreenshot() {
-            try {
-                mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to wait for screen capture result", e);
-            }
-
-            return mScreenshotHardwareBuffer;
-        }
-    }
-
-    /**
-     * A common arguments class used for various screenshot requests. This contains arguments that
-     * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
-     * @hide
-     */
-    private abstract static class CaptureArgs {
-        private final int mPixelFormat;
-        private final Rect mSourceCrop = new Rect();
-        private final float mFrameScaleX;
-        private final float mFrameScaleY;
-        private final boolean mCaptureSecureLayers;
-        private final boolean mAllowProtected;
-        private final long mUid;
-        private final boolean mGrayscale;
-
-        private CaptureArgs(Builder<? extends Builder<?>> builder) {
-            mPixelFormat = builder.mPixelFormat;
-            mSourceCrop.set(builder.mSourceCrop);
-            mFrameScaleX = builder.mFrameScaleX;
-            mFrameScaleY = builder.mFrameScaleY;
-            mCaptureSecureLayers = builder.mCaptureSecureLayers;
-            mAllowProtected = builder.mAllowProtected;
-            mUid = builder.mUid;
-            mGrayscale = builder.mGrayscale;
-        }
-
-        /**
-         * The Builder class used to construct {@link CaptureArgs}
-         *
-         * @param <T> A builder that extends {@link Builder}
-         */
-        abstract static class Builder<T extends Builder<T>> {
-            private int mPixelFormat = PixelFormat.RGBA_8888;
-            private final Rect mSourceCrop = new Rect();
-            private float mFrameScaleX = 1;
-            private float mFrameScaleY = 1;
-            private boolean mCaptureSecureLayers;
-            private boolean mAllowProtected;
-            private long mUid = -1;
-            private boolean mGrayscale;
-
-            /**
-             * The desired pixel format of the returned buffer.
-             */
-            public T setPixelFormat(int pixelFormat) {
-                mPixelFormat = pixelFormat;
-                return getThis();
-            }
-
-            /**
-             * The portion of the screen to capture into the buffer. Caller may pass  in
-             * 'new Rect()' or null if no cropping is desired.
-             */
-            public T setSourceCrop(@Nullable Rect sourceCrop) {
-                if (sourceCrop == null) {
-                    mSourceCrop.setEmpty();
-                } else {
-                    mSourceCrop.set(sourceCrop);
-                }
-                return getThis();
-            }
-
-            /**
-             * The desired scale of the returned buffer. The raw screen will be scaled up/down.
-             */
-            public T setFrameScale(float frameScale) {
-                mFrameScaleX = frameScale;
-                mFrameScaleY = frameScale;
-                return getThis();
-            }
-
-            /**
-             * The desired scale of the returned buffer, allowing separate values for x and y scale.
-             * The raw screen will be scaled up/down.
-             */
-            public T setFrameScale(float frameScaleX, float frameScaleY) {
-                mFrameScaleX = frameScaleX;
-                mFrameScaleY = frameScaleY;
-                return getThis();
-            }
-
-            /**
-             * Whether to allow the screenshot of secure layers. Warning: This should only be done
-             * if the content will be placed in a secure SurfaceControl.
-             *
-             * @see ScreenshotHardwareBuffer#containsSecureLayers()
-             */
-            public T setCaptureSecureLayers(boolean captureSecureLayers) {
-                mCaptureSecureLayers = captureSecureLayers;
-                return getThis();
-            }
-
-            /**
-             * Whether to allow the screenshot of protected (DRM) content. Warning: The screenshot
-             * cannot be read in unprotected space.
-             *
-             * @see HardwareBuffer#USAGE_PROTECTED_CONTENT
-             */
-            public T setAllowProtected(boolean allowProtected) {
-                mAllowProtected = allowProtected;
-                return getThis();
-            }
-
-            /**
-             * Set the uid of the content that should be screenshot. The code will skip any surfaces
-             * that don't belong to the specified uid.
-             */
-            public T setUid(long uid) {
-                mUid = uid;
-                return getThis();
-            }
-
-            /**
-             * Set whether the screenshot should use grayscale or not.
-             */
-            public T setGrayscale(boolean grayscale) {
-                mGrayscale = grayscale;
-                return getThis();
-            }
-
-            /**
-             * Each sub class should return itself to allow the builder to chain properly
-             */
-            abstract T getThis();
-        }
-    }
-
-    /**
-     * The arguments class used to make display capture requests.
-     *
-     * @see #nativeCaptureDisplay(DisplayCaptureArgs, ScreenCaptureListener)
-     * @hide
-     */
-    public static class DisplayCaptureArgs extends CaptureArgs {
-        private final IBinder mDisplayToken;
-        private final int mWidth;
-        private final int mHeight;
-        private final boolean mUseIdentityTransform;
-
-        private DisplayCaptureArgs(Builder builder) {
-            super(builder);
-            mDisplayToken = builder.mDisplayToken;
-            mWidth = builder.mWidth;
-            mHeight = builder.mHeight;
-            mUseIdentityTransform = builder.mUseIdentityTransform;
-        }
-
-        /**
-         * The Builder class used to construct {@link DisplayCaptureArgs}
-         */
-        public static class Builder extends CaptureArgs.Builder<Builder> {
-            private IBinder mDisplayToken;
-            private int mWidth;
-            private int mHeight;
-            private boolean mUseIdentityTransform;
-
-            /**
-             * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
-             * remains valid.
-             */
-            public DisplayCaptureArgs build() {
-                if (mDisplayToken == null) {
-                    throw new IllegalStateException(
-                            "Can't take screenshot with null display token");
-                }
-                return new DisplayCaptureArgs(this);
-            }
-
-            public Builder(IBinder displayToken) {
-                setDisplayToken(displayToken);
-            }
-
-            /**
-             * The display to take the screenshot of.
-             */
-            public Builder setDisplayToken(IBinder displayToken) {
-                mDisplayToken = displayToken;
-                return this;
-            }
-
-            /**
-             * Set the desired size of the returned buffer. The raw screen  will be  scaled down to
-             * this size
-             *
-             * @param width  The desired width of the returned buffer. Caller may pass in 0 if no
-             *               scaling is desired.
-             * @param height The desired height of the returned buffer. Caller may pass in 0 if no
-             *               scaling is desired.
-             */
-            public Builder setSize(int width, int height) {
-                mWidth = width;
-                mHeight = height;
-                return this;
-            }
-
-            /**
-             * Replace the rotation transform of the display with the identity transformation while
-             * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0
-             * orientation. Set this value to false if the screenshot should be taken in the
-             * current screen orientation.
-             */
-            public Builder setUseIdentityTransform(boolean useIdentityTransform) {
-                mUseIdentityTransform = useIdentityTransform;
-                return this;
-            }
-
-            @Override
-            Builder getThis() {
-                return this;
-            }
-        }
-    }
-
-    /**
-     * The arguments class used to make layer capture requests.
-     *
-     * @see #nativeCaptureLayers(LayerCaptureArgs, ScreenCaptureListener)
-     * @hide
-     */
-    public static class LayerCaptureArgs extends CaptureArgs {
-        private final long mNativeLayer;
-        private final long[] mNativeExcludeLayers;
-        private final boolean mChildrenOnly;
-
-        private LayerCaptureArgs(Builder builder) {
-            super(builder);
-            mChildrenOnly = builder.mChildrenOnly;
-            mNativeLayer = builder.mLayer.mNativeObject;
-            if (builder.mExcludeLayers != null) {
-                mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
-                for (int i = 0; i < builder.mExcludeLayers.length; i++) {
-                    mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
-                }
-            } else {
-                mNativeExcludeLayers = null;
-            }
-        }
-
-        /**
-         * The Builder class used to construct {@link LayerCaptureArgs}
-         */
-        public static class Builder extends CaptureArgs.Builder<Builder> {
-            private SurfaceControl mLayer;
-            private SurfaceControl[] mExcludeLayers;
-            private boolean mChildrenOnly = true;
-
-            /**
-             * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
-             * remains valid.
-             */
-            public LayerCaptureArgs build() {
-                if (mLayer == null) {
-                    throw new IllegalStateException(
-                            "Can't take screenshot with null layer");
-                }
-                return new LayerCaptureArgs(this);
-            }
-
-            public Builder(SurfaceControl layer) {
-                setLayer(layer);
-            }
-
-            /**
-             * The root layer to capture.
-             */
-            public Builder setLayer(SurfaceControl layer) {
-                mLayer = layer;
-                return this;
-            }
-
-
-            /**
-             * An array of layer handles to exclude.
-             */
-            public Builder setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
-                mExcludeLayers = excludeLayers;
-                return this;
-            }
-
-            /**
-             * Whether to include the layer itself in the screenshot or just the children and their
-             * descendants.
-             */
-            public Builder setChildrenOnly(boolean childrenOnly) {
-                mChildrenOnly = childrenOnly;
-                return this;
-            }
-
-            @Override
-            Builder getThis() {
-                return this;
-            }
-
-        }
-    }
-
-    /**
      * Builder class for {@link SurfaceControl} objects.
      *
      * By default the surface will be hidden, and have "unset" bounds, meaning it can
@@ -2355,6 +1951,92 @@
     }
 
     /**
+     * Because this API is now going through {@link DisplayManager}, orientation and displayRect
+     * will automatically be computed based on configuration changes. Because of this, the params
+     * orientation and displayRect are ignored
+     *
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+            publicAlternatives = "Use {@code VirtualDisplay#resize(int, int, int)} instead.",
+            trackingBug = 247078497)
+    public static void setDisplayProjection(IBinder displayToken, int orientation,
+            Rect layerStackRect, Rect displayRect) {
+        DisplayManagerGlobal.getInstance().resizeVirtualDisplay(
+                IVirtualDisplayCallback.Stub.asInterface(displayToken), layerStackRect.width(),
+                layerStackRect.height(), 1);
+    }
+
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+            publicAlternatives = "Use {@code MediaProjection#createVirtualDisplay()} with flag "
+                    + " {@code VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for mirroring instead.",
+            trackingBug = 247078497)
+    public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
+        IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
+        if (b == null) {
+            throw new UnsupportedOperationException();
+        }
+
+        IDisplayManager dm = IDisplayManager.Stub.asInterface(b);
+        try {
+            dm.setDisplayIdToMirror(displayToken, layerStack);
+        } catch (RemoteException e) {
+            throw new UnsupportedOperationException(e);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+            publicAlternatives = "Use {@code VirtualDisplay#setSurface(Surface)} instead.",
+            trackingBug = 247078497)
+    public static void setDisplaySurface(IBinder displayToken, Surface surface) {
+        IVirtualDisplayCallback virtualDisplayCallback =
+                IVirtualDisplayCallback.Stub.asInterface(displayToken);
+        DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+        dm.setVirtualDisplaySurface(virtualDisplayCallback, surface);
+    }
+
+    /**
+     * Secure is no longer supported because this is only called from outside system which cannot
+     * create secure displays.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+            publicAlternatives = "Use {@code MediaProjection#createVirtualDisplay()} or "
+                    + "{@code DisplayManager#createVirtualDisplay()} instead.",
+            trackingBug = 247078497)
+    public static IBinder createDisplay(String name, boolean secure) {
+        if (name == null) {
+            throw new IllegalArgumentException("name must not be null");
+        }
+
+        // We don't have a size yet so pass in 1 for width and height since 0 is invalid
+        VirtualDisplay vd = MediaProjectionGlobal.getInstance().createVirtualDisplay(name,
+                1 /* width */, 1 /* height */, INVALID_DISPLAY, null /* Surface */);
+        return vd == null ? null : vd.getToken().asBinder();
+    }
+
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+            publicAlternatives = "Use {@code VirtualDisplay#release()} instead.",
+            trackingBug = 247078497)
+    public static void destroyDisplay(IBinder displayToken) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+
+        DisplayManagerGlobal.getInstance().releaseVirtualDisplay(
+                IVirtualDisplayCallback.Stub.asInterface(displayToken));
+    }
+
+    /**
      * Overrides HDR modes for a display device.
      *
      * If the caller does not have ACCESS_SURFACE_FLINGER permission, this will throw a Security
@@ -2369,28 +2051,6 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
-    public static IBinder createDisplay(String name, boolean secure) {
-        if (name == null) {
-            throw new IllegalArgumentException("name must not be null");
-        }
-        return nativeCreateDisplay(name, secure);
-    }
-
-    /**
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static void destroyDisplay(IBinder displayToken) {
-        if (displayToken == null) {
-            throw new IllegalArgumentException("displayToken must not be null");
-        }
-        nativeDestroyDisplay(displayToken);
-    }
-
-    /**
-     * @hide
-     */
     public static long[] getPhysicalDisplayIds() {
         return nativeGetPhysicalDisplayIds();
     }
@@ -2418,119 +2078,6 @@
     }
 
     /**
-     * @param captureArgs Arguments about how to take the screenshot
-     * @param captureListener A listener to receive the screenshot callback
-     * @hide
-     */
-    public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
-            @NonNull ScreenCaptureListener captureListener) {
-        return nativeCaptureDisplay(captureArgs, captureListener);
-    }
-
-    /**
-     * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with
-     * the content.
-     *
-     * @hide
-     */
-    public static ScreenshotHardwareBuffer captureDisplay(DisplayCaptureArgs captureArgs) {
-        SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
-
-        int status = captureDisplay(captureArgs, screenCaptureListener);
-        if (status != 0) {
-            return null;
-        }
-
-        return screenCaptureListener.waitForScreenshot();
-    }
-
-    /**
-     * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
-     *
-     * @param layer            The root layer to capture.
-     * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
-     *                         Rect()' or null if no cropping is desired. If the root layer does not
-     *                         have a buffer or a crop set, then a non-empty source crop must be
-     *                         specified.
-     * @param frameScale       The desired scale of the returned buffer; the raw
-     *                         screen will be scaled up/down.
-     *
-     * @return Returns a HardwareBuffer that contains the layer capture.
-     * @hide
-     */
-    public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
-            float frameScale) {
-        return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
-    }
-
-    /**
-     * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
-     *
-     * @param layer            The root layer to capture.
-     * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
-     *                         Rect()' or null if no cropping is desired. If the root layer does not
-     *                         have a buffer or a crop set, then a non-empty source crop must be
-     *                         specified.
-     * @param frameScale       The desired scale of the returned buffer; the raw
-     *                         screen will be scaled up/down.
-     * @param format           The desired pixel format of the returned buffer.
-     *
-     * @return Returns a HardwareBuffer that contains the layer capture.
-     * @hide
-     */
-    public static ScreenshotHardwareBuffer captureLayers(@NonNull SurfaceControl layer,
-            @Nullable Rect sourceCrop, float frameScale, int format) {
-        LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
-                .setSourceCrop(sourceCrop)
-                .setFrameScale(frameScale)
-                .setPixelFormat(format)
-                .build();
-
-        return captureLayers(captureArgs);
-    }
-
-    /**
-     * @hide
-     */
-    public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
-        SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
-
-        int status = captureLayers(captureArgs, screenCaptureListener);
-        if (status != 0) {
-            return null;
-        }
-
-        return screenCaptureListener.waitForScreenshot();
-    }
-
-    /**
-     * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
-     * handles to exclude.
-     * @hide
-     */
-    public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
-            Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
-        LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
-                .setSourceCrop(sourceCrop)
-                .setFrameScale(frameScale)
-                .setPixelFormat(format)
-                .setExcludeLayers(exclude)
-                .build();
-
-        return captureLayers(captureArgs);
-    }
-
-    /**
-     * @param captureArgs Arguments about how to take the screenshot
-     * @param captureListener A listener to receive the screenshot callback
-     * @hide
-     */
-    public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
-            @NonNull ScreenCaptureListener captureListener) {
-        return nativeCaptureLayers(captureArgs, captureListener);
-    }
-
-    /**
      * Returns whether protected content is supported in GPU composition.
      * @hide
      */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b6c92e3..9075de1 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -107,6 +107,14 @@
  * and scaling a SurfaceView on screen will not cause rendering artifacts. Such
  * artifacts may occur on previous versions of the platform when its window is
  * positioned asynchronously.</p>
+ *
+ * <p class="note"><strong>Note:</strong> Starting in platform version
+ * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, SurfaceView will support arbitrary
+ * alpha blending. Prior platform versions ignored alpha values on the SurfaceView if they were
+ * between 0 and 1. If the SurfaceView is configured with Z-above, then the alpha is applied
+ * directly to the Surface. If the SurfaceView is configured with Z-below, then the alpha is
+ * applied to the hole punch directly. Note that when using Z-below, overlapping SurfaceViews
+ * may not blend properly as a consequence of not applying alpha to the surface content directly.
  */
 public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
     private static final String TAG = "SurfaceView";
@@ -146,6 +154,7 @@
     Paint mRoundedViewportPaint;
 
     int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
+    int mRequestedSubLayer = APPLICATION_MEDIA_SUBLAYER;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     boolean mIsCreating = false;
@@ -177,8 +186,7 @@
     @UnsupportedAppUsage
     int mRequestedFormat = PixelFormat.RGB_565;
 
-    boolean mUseAlpha = false;
-    float mSurfaceAlpha = 1f;
+    float mAlpha = 1f;
     boolean mClipSurfaceToBounds;
     int mBackgroundColor = Color.BLACK;
 
@@ -335,58 +343,25 @@
      * @hide
      */
     public void setUseAlpha() {
-        if (!mUseAlpha) {
-            mUseAlpha = true;
-            updateSurfaceAlpha();
-        }
+        // TODO(b/241474646): Remove me
+        return;
     }
 
     @Override
     public void setAlpha(float alpha) {
-        // Sets the opacity of the view to a value, where 0 means the view is completely transparent
-        // and 1 means the view is completely opaque.
-        //
-        // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
-        // to call setUseAlpha() as well.
-        // This view doesn't support translucent opacity if the view is located z-below, since the
-        // logic to punch a hole in the view hierarchy cannot handle such case. See also
-        // #clearSurfaceViewPort(Canvas)
         if (DEBUG) {
             Log.d(TAG, System.identityHashCode(this)
-                    + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
+                    + " setAlpha: alpha=" + alpha);
         }
         super.setAlpha(alpha);
-        updateSurfaceAlpha();
     }
 
-    private float getFixedAlpha() {
-        // Compute alpha value to be set on the underlying surface.
-        final float alpha = getAlpha();
-        return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
-    }
-
-    private void updateSurfaceAlpha() {
-        if (!mUseAlpha || !mHaveFrame || mSurfaceControl == null) {
-            return;
+    @Override
+    protected boolean onSetAlpha(int alpha) {
+        if (Math.round(mAlpha * 255) != alpha) {
+            updateSurface();
         }
-        final float viewAlpha = getAlpha();
-        if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
-            Log.w(TAG, System.identityHashCode(this)
-                    + " updateSurfaceAlpha:"
-                    + " translucent color is not supported for a surface placed z-below.");
-        }
-        final ViewRootImpl viewRoot = getViewRootImpl();
-        if (viewRoot == null) {
-            return;
-        }
-        final float alpha = getFixedAlpha();
-        if (alpha != mSurfaceAlpha) {
-            final Transaction transaction = new Transaction();
-            transaction.setAlpha(mSurfaceControl, alpha);
-            viewRoot.applyTransactionOnDraw(transaction);
-            damageInParent();
-            mSurfaceAlpha = alpha;
-        }
+        return true;
     }
 
     private void performDrawFinished() {
@@ -534,7 +509,15 @@
         invalidate();
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        // SurfaceViews only alpha composite by modulating the Surface alpha for Z-above, or
+        // applying alpha on the hole punch for Z-below - no deferral to a layer is necessary.
+        return false;
+    }
+
     private void clearSurfaceViewPort(Canvas canvas) {
+        final float alpha = getAlpha();
         if (mCornerRadius > 0f) {
             canvas.getClipBounds(mTmpRect);
             if (mClipSurfaceToBounds && mClipBounds != null) {
@@ -546,10 +529,11 @@
                     mTmpRect.right,
                     mTmpRect.bottom,
                     mCornerRadius,
-                    mCornerRadius
+                    mCornerRadius,
+                    alpha
             );
         } else {
-            canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f);
+            canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f, alpha);
         }
     }
 
@@ -626,7 +610,7 @@
      * @hide
      */
     public boolean isZOrderedOnTop() {
-        return mSubLayer > 0;
+        return mRequestedSubLayer > 0;
     }
 
     /**
@@ -652,10 +636,10 @@
         } else {
             subLayer = APPLICATION_MEDIA_SUBLAYER;
         }
-        if (mSubLayer == subLayer) {
+        if (mRequestedSubLayer == subLayer) {
             return false;
         }
-        mSubLayer = subLayer;
+        mRequestedSubLayer = subLayer;
 
         if (!allowDynamicChange) {
             return false;
@@ -667,9 +651,8 @@
         if (viewRoot == null) {
             return true;
         }
-        final Transaction transaction = new SurfaceControl.Transaction();
-        updateRelativeZ(transaction);
-        viewRoot.applyTransactionOnDraw(transaction);
+
+        updateSurface();
         invalidate();
         return true;
     }
@@ -722,8 +705,7 @@
     }
 
     private void releaseSurfaces(boolean releaseSurfacePackage) {
-        mSurfaceAlpha = 1f;
-
+        mAlpha = 1f;
         synchronized (mSurfaceControlLock) {
             mSurface.destroy();
             if (mBlastBufferQueue != null) {
@@ -770,7 +752,7 @@
     }
 
     private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
-            boolean creating, boolean sizeChanged, boolean hintChanged,
+            boolean creating, boolean sizeChanged, boolean hintChanged, boolean relativeZChanged,
             Transaction surfaceUpdateTransaction) {
         boolean realSizeChanged = false;
 
@@ -800,14 +782,20 @@
                 surfaceUpdateTransaction.hide(mSurfaceControl);
             }
 
-
-
             updateBackgroundVisibility(surfaceUpdateTransaction);
             updateBackgroundColor(surfaceUpdateTransaction);
-            if (mUseAlpha) {
-                float alpha = getFixedAlpha();
+            if (isAboveParent()) {
+                float alpha = getAlpha();
                 surfaceUpdateTransaction.setAlpha(mSurfaceControl, alpha);
-                mSurfaceAlpha = alpha;
+            }
+
+            if (relativeZChanged) {
+                if (!isAboveParent()) {
+                    // If we're moving from z-above to z-below, then restore the surface alpha back to 1
+                    // and let the holepunch drive visibility and blending.
+                    surfaceUpdateTransaction.setAlpha(mSurfaceControl, 1.f);
+                }
+                updateRelativeZ(surfaceUpdateTransaction);
             }
 
             surfaceUpdateTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
@@ -873,6 +861,7 @@
         } finally {
             mSurfaceLock.unlock();
         }
+
         return realSizeChanged;
     }
 
@@ -906,10 +895,10 @@
         int myHeight = mRequestedHeight;
         if (myHeight <= 0) myHeight = getHeight();
 
-        final float alpha = getFixedAlpha();
+        final float alpha = getAlpha();
         final boolean formatChanged = mFormat != mRequestedFormat;
         final boolean visibleChanged = mVisible != mRequestedVisible;
-        final boolean alphaChanged = mSurfaceAlpha != alpha;
+        final boolean alphaChanged = mAlpha != alpha;
         final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
                 && mRequestedVisible;
         final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
@@ -921,17 +910,17 @@
             || getHeight() != mScreenRect.height();
         final boolean hintChanged = (viewRoot.getBufferTransformHint() != mTransformHint)
                 && mRequestedVisible;
+        final boolean relativeZChanged = mSubLayer != mRequestedSubLayer;
 
-        if (creating || formatChanged || sizeChanged || visibleChanged ||
-                (mUseAlpha && alphaChanged) || windowVisibleChanged ||
-                positionChanged || layoutSizeChanged || hintChanged) {
+        if (creating || formatChanged || sizeChanged || visibleChanged
+                || alphaChanged || windowVisibleChanged || positionChanged
+                || layoutSizeChanged || hintChanged || relativeZChanged) {
 
             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
                     + "Changes: creating=" + creating
                     + " format=" + formatChanged + " size=" + sizeChanged
                     + " visible=" + visibleChanged + " alpha=" + alphaChanged
                     + " hint=" + hintChanged
-                    + " mUseAlpha=" + mUseAlpha
                     + " visible=" + visibleChanged
                     + " left=" + (mWindowSpaceLeft != mLocation[0])
                     + " top=" + (mWindowSpaceTop != mLocation[1]));
@@ -943,8 +932,10 @@
                 mSurfaceWidth = myWidth;
                 mSurfaceHeight = myHeight;
                 mFormat = mRequestedFormat;
+                mAlpha = alpha;
                 mLastWindowVisibility = mWindowVisibility;
                 mTransformHint = viewRoot.getBufferTransformHint();
+                mSubLayer = mRequestedSubLayer;
 
                 mScreenRect.left = mWindowSpaceLeft;
                 mScreenRect.top = mWindowSpaceTop;
@@ -968,7 +959,7 @@
                 }
 
                 final boolean redrawNeeded = sizeChanged || creating || hintChanged
-                        || (mVisible && !mDrawFinished);
+                        || (mVisible && !mDrawFinished) || alphaChanged || relativeZChanged;
                 boolean shouldSyncBuffer =
                         redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInLocalSync();
                 SyncBufferTransactionCallback syncBufferTransactionCallback = null;
@@ -979,8 +970,9 @@
                             syncBufferTransactionCallback::onTransactionReady);
                 }
 
-                final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
-                        translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
+                final boolean realSizeChanged = performSurfaceTransaction(viewRoot, translator,
+                        creating, sizeChanged, hintChanged, relativeZChanged,
+                        surfaceUpdateTransaction);
 
                 try {
                     SurfaceHolder.Callback[] callbacks = null;
@@ -1622,8 +1614,11 @@
          */
         @Override
         public void unlockCanvasAndPost(Canvas canvas) {
-            mSurface.unlockCanvasAndPost(canvas);
-            mSurfaceLock.unlock();
+            try {
+                mSurface.unlockCanvasAndPost(canvas);
+            } finally {
+                mSurfaceLock.unlock();
+            }
         }
 
         @Override
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index 2d4da2c..a52fc75 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -180,9 +180,9 @@
     private static native void nativeClear(long ptr);
     private static native void nativeAddMovement(long ptr, MotionEvent event);
     private static native void nativeComputeCurrentVelocity(long ptr, int units, float maxVelocity);
-    private static native float nativeGetXVelocity(long ptr, int id);
-    private static native float nativeGetYVelocity(long ptr, int id);
-    private static native boolean nativeGetEstimator(long ptr, int id, Estimator outEstimator);
+    private static native float nativeGetVelocity(long ptr, int axis, int id);
+    private static native boolean nativeGetEstimator(
+            long ptr, int axis, int id, Estimator outEstimator);
 
     static {
         // Strategy string and IDs mapping lookup.
@@ -361,7 +361,7 @@
      * @return The previously computed X velocity.
      */
     public float getXVelocity() {
-        return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
+        return getXVelocity(ACTIVE_POINTER_ID);
     }
 
     /**
@@ -371,7 +371,7 @@
      * @return The previously computed Y velocity.
      */
     public float getYVelocity() {
-        return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
+        return getYVelocity(ACTIVE_POINTER_ID);
     }
 
     /**
@@ -382,7 +382,7 @@
      * @return The previously computed X velocity.
      */
     public float getXVelocity(int id) {
-        return nativeGetXVelocity(mPtr, id);
+        return nativeGetVelocity(mPtr, MotionEvent.AXIS_X, id);
     }
 
     /**
@@ -393,7 +393,7 @@
      * @return The previously computed Y velocity.
      */
     public float getYVelocity(int id) {
-        return nativeGetYVelocity(mPtr, id);
+        return nativeGetVelocity(mPtr, MotionEvent.AXIS_Y, id);
     }
 
     /**
@@ -403,6 +403,8 @@
      * It is not necessary to call {@link #computeCurrentVelocity(int)} before calling
      * this method.
      *
+     * @param axis Which axis's velocity to return.
+     *             Should be one of the axes defined in {@link MotionEvent}.
      * @param id Which pointer's velocity to return.
      * @param outEstimator The estimator to populate.
      * @return True if an estimator was obtained, false if there is no information
@@ -410,11 +412,11 @@
      *
      * @hide For internal use only.  Not a final API.
      */
-    public boolean getEstimator(int id, Estimator outEstimator) {
+    public boolean getEstimator(int axis, int id, Estimator outEstimator) {
         if (outEstimator == null) {
             throw new IllegalArgumentException("outEstimator must not be null");
         }
-        return nativeGetEstimator(mPtr, id, outEstimator);
+        return nativeGetEstimator(mPtr, axis, id, outEstimator);
     }
 
     /**
@@ -434,16 +436,9 @@
         private static final int MAX_DEGREE = 4;
 
         /**
-         * Polynomial coefficients describing motion in X.
+         * Polynomial coefficients describing motion.
          */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public final float[] xCoeff = new float[MAX_DEGREE + 1];
-
-        /**
-         * Polynomial coefficients describing motion in Y.
-         */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public final float[] yCoeff = new float[MAX_DEGREE + 1];
+        public final float[] coeff = new float[MAX_DEGREE + 1];
 
         /**
          * Polynomial degree, or zero if only position information is available.
@@ -458,39 +453,21 @@
         public float confidence;
 
         /**
-         * Gets an estimate of the X position of the pointer at the specified time point.
+         * Gets an estimate of the position of the pointer at the specified time point.
          * @param time The time point in seconds, 0 is the last recorded time.
-         * @return The estimated X coordinate.
+         * @return The estimated axis value.
          */
-        public float estimateX(float time) {
-            return estimate(time, xCoeff);
+        public float estimate(float time) {
+            return estimate(time, coeff);
         }
 
         /**
-         * Gets an estimate of the Y position of the pointer at the specified time point.
-         * @param time The time point in seconds, 0 is the last recorded time.
-         * @return The estimated Y coordinate.
-         */
-        public float estimateY(float time) {
-            return estimate(time, yCoeff);
-        }
-
-        /**
-         * Gets the X coefficient with the specified index.
+         * Gets the coefficient with the specified index.
          * @param index The index of the coefficient to return.
-         * @return The X coefficient, or 0 if the index is greater than the degree.
+         * @return The coefficient, or 0 if the index is greater than the degree.
          */
-        public float getXCoeff(int index) {
-            return index <= degree ? xCoeff[index] : 0;
-        }
-
-        /**
-         * Gets the Y coefficient with the specified index.
-         * @param index The index of the coefficient to return.
-         * @return The Y coefficient, or 0 if the index is greater than the degree.
-         */
-        public float getYCoeff(int index) {
-            return index <= degree ? yCoeff[index] : 0;
+        public float getCoeff(int index) {
+            return index <= degree ? coeff[index] : 0;
         }
 
         private float estimate(float time, float[] c) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3b8b479..15aa4b4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -62,6 +62,7 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.ColorStateList;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -3094,7 +3095,6 @@
      * <p>
      * Accessibility interactions from services without {@code isAccessibilityTool} set to true are
      * disallowed for any of the following conditions:
-     * <li>this view's window sets {@link WindowManager.LayoutParams#FLAG_SECURE}.</li>
      * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li>
      * <li>any parent of this view returns true from {@link #isAccessibilityDataPrivate()}.</li>
      * </p>
@@ -8325,10 +8325,17 @@
 
     /**
      * Visually distinct portion of a window with window-like semantics are considered panes for
-     * accessibility purposes. One example is the content view of a fragment that is replaced.
+     * accessibility purposes. One example is the content view of a large fragment that is replaced.
      * In order for accessibility services to understand a pane's window-like behavior, panes
-     * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s
-     * when they appear, disappear, or change title.
+     * should have descriptive titles. Views with pane titles produce
+     * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}s when they appear, disappear, or change
+     * title.
+     *
+     * <p>
+     * When transitioning from one Activity to another, instead of using
+     * setAccessibilityPaneTitle(), set a descriptive title for its window by using android:label
+     * for the matching <activity> entry in your application’s manifest or updating the title at
+     * runtime with{@link android.app.Activity#setTitle(CharSequence)}.
      *
      * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this
      *                               View is not a pane.
@@ -10994,8 +11001,19 @@
      * description. An image of a floppy disk that is used to save a file may
      * use "Save".
      *
+     * <p>
+     * This should omit role or state. Role refers to the kind of user-interface element the View
+     * is, such as a Button or Checkbox. State refers to a frequently changing property of the View,
+     * such as an On/Off state of a button or the audio level of a volume slider.
+     *
+     * <p>
+     * Content description updates are not frequent, and are used when the semantic content - not
+     * the state - of the element changes. For example, a Play button might change to a Pause
+     * button during music playback.
+     *
      * @param contentDescription The content description.
      * @see #getContentDescription()
+     * @see #setStateDescription(CharSequence)} for state changes.
      * @attr ref android.R.styleable#View_contentDescription
      */
     @RemotableViewMethod
@@ -12889,7 +12907,6 @@
         if (mViewTranslationCallback != null) {
             mViewTranslationCallback.onClearTranslation(this);
         }
-        clearViewTranslationCallback();
         clearViewTranslationResponse();
         if (hasTranslationTransientState()) {
             setHasTransientState(false);
@@ -13897,6 +13914,11 @@
      * See also {@link #focusSearch(int)}, which is what you call to say that you
      * have focus, and you want your parent to look for the next one.
      *
+     * <p>
+     * <b>Note:</b> Avoid setting accessibility focus. This is intended to be controlled by screen
+     * readers. Apps changing focus can confuse screen readers, so the resulting behavior can vary
+     * by device and screen reader version.
+     *
      * @return Whether this view actually took accessibility focus.
      *
      * @hide
@@ -14508,9 +14530,6 @@
         // Use the explicit value if set.
         if (mExplicitAccessibilityDataPrivate != ACCESSIBILITY_DATA_PRIVATE_AUTO) {
             mInferredAccessibilityDataPrivate = mExplicitAccessibilityDataPrivate;
-        } else if (mAttachInfo != null && mAttachInfo.mWindowSecure) {
-            // Views inside FLAG_SECURE windows default to accessibilityDataPrivate.
-            mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES;
         } else if (getFilterTouchesWhenObscured()) {
             // Views that set filterTouchesWhenObscured default to accessibilityDataPrivate.
             mInferredAccessibilityDataPrivate = ACCESSIBILITY_DATA_PRIVATE_YES;
@@ -14735,6 +14754,12 @@
      * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if
      * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p>
      *
+     * <p>
+     * <b>Note:</b> Avoid setting accessibility focus with
+     * {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS}. This is intended to be controlled
+     * by screen readers. Apps changing focus can confuse screen readers, so the resulting behavior
+     * can vary by device and screen reader version.
+     *
      * @param action The action to perform.
      * @param arguments Optional action arguments.
      * @return Whether the action was performed.
@@ -24490,8 +24515,9 @@
     /**
      * Set the current default focus highlight.
      * @param highlight the highlight drawable, or {@code null} if it's no longer needed.
+     * @hide
      */
-    private void setDefaultFocusHighlight(Drawable highlight) {
+    void setDefaultFocusHighlight(Drawable highlight) {
         mDefaultFocusHighlight = highlight;
         mDefaultFocusHighlightSizeChanged = true;
         if (highlight != null) {
@@ -27546,6 +27572,11 @@
                 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) {
             throw new IllegalStateException("Drag shadow dimensions must not be negative");
         }
+        final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale();
+        if (overrideInvScale != 1f) {
+            shadowTouchPoint.x = (int) (shadowTouchPoint.x / overrideInvScale);
+            shadowTouchPoint.y = (int) (shadowTouchPoint.y / overrideInvScale);
+        }
 
         // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder
         // does not accept zero size surface.
@@ -27570,6 +27601,11 @@
                 .setFormat(PixelFormat.TRANSLUCENT)
                 .setCallsite("View.startDragAndDrop")
                 .build();
+        if (overrideInvScale != 1f) {
+            final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+            transaction.setMatrix(surfaceControl, 1 / overrideInvScale, 0, 0, 1 / overrideInvScale)
+                    .apply();
+        }
         final Surface surface = new Surface();
         surface.copyFrom(surfaceControl);
         IBinder token = null;
@@ -30222,11 +30258,6 @@
         int mWindowVisibility;
 
         /**
-         * Indicates whether the view's window sets {@link WindowManager.LayoutParams#FLAG_SECURE}.
-         */
-        boolean mWindowSecure;
-
-        /**
          * Indicates the time at which drawing started to occur.
          */
         @UnsupportedAppUsage
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 864ea21..4b16788 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1787,6 +1787,7 @@
 
         final ClientWindowFrames frames = (ClientWindowFrames) args.arg1;
         final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
+        CompatibilityInfo.applyOverrideScaleIfNeeded(mergedConfiguration);
         final boolean forceNextWindowRelayout = args.argi1 != 0;
         final int displayId = args.argi3;
         final int resizeMode = args.argi5;
@@ -2058,6 +2059,7 @@
     }
 
     private void invalidateRectOnScreen(Rect dirty) {
+        if (DEBUG_DRAW) Log.v(mTag, "invalidateRectOnScreen: " + dirty);
         final Rect localDirty = mDirty;
 
         // Add the new dirty rect to the current one
@@ -2836,7 +2838,6 @@
             // However, windows are now always 32 bits by default, so choose 32 bits
             mAttachInfo.mUse32BitDrawingCache = true;
             mAttachInfo.mWindowVisibility = viewVisibility;
-            mAttachInfo.mWindowSecure = (lp.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0;
             mAttachInfo.mRecomputeGlobalAttributes = false;
             mLastConfigurationFromResources.setTo(config);
             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
@@ -3813,6 +3814,13 @@
                 if (mAttachInfo.mTooltipHost != null) {
                     mAttachInfo.mTooltipHost.hideTooltip();
                 }
+                if (!hasWindowFocus) {
+                    // Clear focus highlight if its window lost focus.
+                    final View focused = mView.findFocus();
+                    if (focused != null) {
+                        focused.setDefaultFocusHighlight(null);
+                    }
+                }
             }
 
             // Note: must be done after the focus change callbacks,
@@ -4751,25 +4759,8 @@
         // Draw with software renderer.
         final Canvas canvas;
 
-        // We already have the offset of surfaceInsets in xoff, yoff and dirty region,
-        // therefore we need to add it back when moving the dirty region.
-        int dirtyXOffset = xoff;
-        int dirtyYOffset = yoff;
-        if (surfaceInsets != null) {
-            dirtyXOffset += surfaceInsets.left;
-            dirtyYOffset += surfaceInsets.top;
-        }
-
         try {
-            dirty.offset(-dirtyXOffset, -dirtyYOffset);
-            final int left = dirty.left;
-            final int top = dirty.top;
-            final int right = dirty.right;
-            final int bottom = dirty.bottom;
-
             canvas = mSurface.lockCanvas(dirty);
-
-            // TODO: Do this in native
             canvas.setDensity(mDensity);
         } catch (Surface.OutOfResourcesException e) {
             handleOutOfResourcesException(e);
@@ -4781,14 +4772,13 @@
             // kill stuff (or ourself) for no reason.
             mLayoutRequested = true;    // ask wm for a new surface next time.
             return false;
-        } finally {
-            dirty.offset(dirtyXOffset, dirtyYOffset);  // Reset to the original value.
         }
 
         try {
             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                 Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
-                        + canvas.getWidth() + ", h=" + canvas.getHeight());
+                        + canvas.getWidth() + ", h=" + canvas.getHeight() + ", dirty: " + dirty
+                        + ", xOff=" + xoff + ", yOff=" + yoff);
                 //canvas.drawARGB(255, 255, 0, 0);
             }
 
@@ -5862,7 +5852,13 @@
             // be when the window is first being added, and mFocused isn't
             // set yet.
             final View focused = mView.findFocus();
-            if (focused != null && !focused.isFocusableInTouchMode()) {
+            if (focused == null) {
+                return false;
+            }
+
+            // Clear default focus highlight if it entered touch mode.
+            focused.setDefaultFocusHighlight(null);
+            if (!focused.isFocusableInTouchMode()) {
                 final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
                 if (ancestorToTakeFocus != null) {
                     // there is an ancestor that wants focus after its
@@ -8229,6 +8225,7 @@
                     mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
                     mTempInsets, mTempControls, mRelayoutBundle);
             mRelayoutRequested = true;
+
             final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
             if (maybeSyncSeqId > 0) {
                 mSyncSeqId = maybeSyncSeqId;
@@ -8242,6 +8239,7 @@
                 mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
             }
             mInvSizeCompatScale = 1f / mTmpFrames.sizeCompatScale;
+            CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration);
             mInsetsController.onStateChanged(mTempInsets);
             mInsetsController.onControlsChanged(mTempControls);
 
@@ -8268,6 +8266,12 @@
             }
         }
 
+        if (mSurfaceControl.isValid() && !HardwareRenderer.isDrawingEnabled()) {
+            // When drawing is disabled the window layer won't have a valid buffer.
+            // Set a window crop so input can get delivered to the window.
+            mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
+        }
+
         mLastTransformHint = transformHint;
       
         mSurfaceControl.setTransformHint(transformHint);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a49caaf..8656af2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -285,12 +285,18 @@
     int TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
 
     /**
-     * Keyguard is being occluded.
+     * Keyguard is being occluded by non-Dream.
      * @hide
      */
     int TRANSIT_OLD_KEYGUARD_OCCLUDE = 22;
 
     /**
+     * Keyguard is being occluded by Dream.
+     * @hide
+     */
+    int TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM = 33;
+
+    /**
      * Keyguard is being unoccluded.
      * @hide
      */
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 2db0dcb..f2c8355 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
+import android.widget.TextView;
 
 import com.android.internal.util.BitUtils;
 
@@ -685,6 +686,18 @@
      */
     public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200;
 
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+     * It means the content is invalid or associated with an error.
+     * For example, text that sets an error message, such as when input isn't in a valid format,
+     * should send this event and use {@link AccessibilityNodeInfo#setError} to
+     * provide more context.
+     *
+     * @see AccessibilityNodeInfo#setError
+     * @see TextView#setError
+     */
+    public static final int CONTENT_CHANGE_TYPE_INVALID = 0x0000400;
+
     /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */
     public static final int SPEECH_STATE_SPEAKING_START = 0x00000001;
 
@@ -810,6 +823,7 @@
                 CONTENT_CHANGE_TYPE_DRAG_STARTED,
                 CONTENT_CHANGE_TYPE_DRAG_DROPPED,
                 CONTENT_CHANGE_TYPE_DRAG_CANCELLED,
+                CONTENT_CHANGE_TYPE_INVALID,
             })
     public @interface ContentChangeTypes {}
 
@@ -1076,6 +1090,7 @@
             case CONTENT_CHANGE_TYPE_DRAG_STARTED: return "CONTENT_CHANGE_TYPE_DRAG_STARTED";
             case CONTENT_CHANGE_TYPE_DRAG_DROPPED: return "CONTENT_CHANGE_TYPE_DRAG_DROPPED";
             case CONTENT_CHANGE_TYPE_DRAG_CANCELLED: return "CONTENT_CHANGE_TYPE_DRAG_CANCELLED";
+            case CONTENT_CHANGE_TYPE_INVALID: return "CONTENT_CHANGE_TYPE_INVALID";
             default: return Integer.toHexString(type);
         }
     }
@@ -1332,6 +1347,7 @@
      * Convenience method to obtain a {@link #TYPE_WINDOWS_CHANGED} event for a specific window and
      * change set.
      *
+     * @param displayId The ID of the display from which the event comes from
      * @param windowId The ID of the window that changed
      * @param windowChangeTypes The changes to populate
      * @return An instance of a TYPE_WINDOWS_CHANGED, populated with the requested fields and with
@@ -1340,8 +1356,9 @@
      * @hide
      */
     public static AccessibilityEvent obtainWindowsChangedEvent(
-            int windowId, int windowChangeTypes) {
+            int displayId, int windowId, int windowChangeTypes) {
         final AccessibilityEvent event = new AccessibilityEvent(TYPE_WINDOWS_CHANGED);
+        event.setDisplayId(displayId);
         event.setWindowId(windowId);
         event.setWindowChanges(windowChangeTypes);
         event.setImportantForAccessibility(true);
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index e89f836..7528e2a 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -585,6 +585,18 @@
 
     /**
      * Returns if the accessibility in the system is enabled.
+     * <p>
+     * <b>Note:</b> This query is used for sending {@link AccessibilityEvent}s, since events are
+     * only needed if accessibility is on. Avoid changing UI or app behavior based on the state of
+     * accessibility. While well-intentioned, doing this creates brittle, less
+     * well-maintained code that works for some users but not others. Shared code leads to more
+     * equitable experiences and less technical debt.
+     *
+     *<p>
+     * For example, if you want to expose a unique interaction with your app, use
+     * ViewCompat#addAccessibilityAction in AndroidX to make this interaction - ideally
+     * with the same code path used for non-accessibility users - available to accessibility
+     * services. Services can then expose this action in the way best fit for their users.
      *
      * @return True if accessibility is enabled, false otherwise.
      */
@@ -597,6 +609,13 @@
 
     /**
      * Returns if the touch exploration in the system is enabled.
+     * <p>
+     * <b>Note:</b> This query is used for dispatching hover events, such as
+     * {@link android.view.MotionEvent#ACTION_HOVER_ENTER}, to accessibility services to manage
+     * touch exploration. Avoid changing UI or app behavior based on the state of accessibility.
+     * While well-intentioned, doing this creates brittle, less well-maintained code that works for
+     * som users but not others. Shared code leads to more equitable experiences and less technical
+     * debt.
      *
      * @return True if touch exploration is enabled, false otherwise.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1f33806..d07a797 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -4829,6 +4829,9 @@
 
         /**
          * Action that gives accessibility focus to the node.
+         * <p>
+         * This is intended to be used by screen readers. Apps changing focus can confuse screen
+         * readers, so the resulting behavior can vary by device and screen reader version.
          */
         public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
                 new AccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 624937f..8d75072 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -20,6 +20,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -61,8 +62,15 @@
     static final Object COMPOSING = new ComposingText();
 
     /** @hide */
-    protected final InputMethodManager mIMM;
-    final View mTargetView;
+    @NonNull protected final InputMethodManager mIMM;
+
+    /**
+     * Target view for the input connection.
+     *
+     * <p>This could be null for a fallback input connection.
+     */
+    @Nullable final View mTargetView;
+
     final boolean mFallbackMode;
 
     private Object[] mDefaultComposingSpans;
@@ -70,20 +78,25 @@
     Editable mEditable;
     KeyCharacterMap mKeyCharacterMap;
 
-    BaseInputConnection(InputMethodManager mgr, boolean fullEditor) {
+    BaseInputConnection(@NonNull InputMethodManager mgr, boolean fullEditor) {
         mIMM = mgr;
         mTargetView = null;
         mFallbackMode = !fullEditor;
     }
 
-    public BaseInputConnection(View targetView, boolean fullEditor) {
+    public BaseInputConnection(@NonNull View targetView, boolean fullEditor) {
         mIMM = (InputMethodManager)targetView.getContext().getSystemService(
                 Context.INPUT_METHOD_SERVICE);
         mTargetView = targetView;
         mFallbackMode = !fullEditor;
     }
 
-    public static final void removeComposingSpans(Spannable text) {
+    /**
+     * Removes the composing spans from the given text if any.
+     *
+     * @param text the spannable text to remove composing spans
+     */
+    public static final void removeComposingSpans(@NonNull Spannable text) {
         text.removeSpan(COMPOSING);
         Object[] sps = text.getSpans(0, text.length(), Object.class);
         if (sps != null) {
@@ -96,12 +109,17 @@
         }
     }
 
-    public static void setComposingSpans(Spannable text) {
+    /**
+     * Removes the composing spans from the given text if any.
+     *
+     * @param text the spannable text to remove composing spans
+     */
+    public static void setComposingSpans(@NonNull Spannable text) {
         setComposingSpans(text, 0, text.length());
     }
 
     /** @hide */
-    public static void setComposingSpans(Spannable text, int start, int end) {
+    public static void setComposingSpans(@NonNull Spannable text, int start, int end) {
         final Object[] sps = text.getSpans(start, end, Object.class);
         if (sps != null) {
             for (int i=sps.length-1; i>=0; i--) {
@@ -114,7 +132,10 @@
                 final int fl = text.getSpanFlags(o);
                 if ((fl & (Spanned.SPAN_COMPOSING | Spanned.SPAN_POINT_MARK_MASK))
                         != (Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
-                    text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
+                    text.setSpan(
+                            o,
+                            text.getSpanStart(o),
+                            text.getSpanEnd(o),
                             (fl & ~Spanned.SPAN_POINT_MARK_MASK)
                                     | Spanned.SPAN_COMPOSING
                                     | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -126,20 +147,24 @@
                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
     }
 
-    public static int getComposingSpanStart(Spannable text) {
+    /** Return the beginning of the range of composing text, or -1 if there's no composing text. */
+    public static int getComposingSpanStart(@NonNull Spannable text) {
         return text.getSpanStart(COMPOSING);
     }
 
-    public static int getComposingSpanEnd(Spannable text) {
+    /** Return the end of the range of composing text, or -1 if there's no composing text. */
+    public static int getComposingSpanEnd(@NonNull Spannable text) {
         return text.getSpanEnd(COMPOSING);
     }
 
     /**
-     * Return the target of edit operations.  The default implementation
-     * returns its own fake editable that is just used for composing text;
-     * subclasses that are real text editors should override this and
-     * supply their own.
+     * Return the target of edit operations. The default implementation returns its own fake
+     * editable that is just used for composing text; subclasses that are real text editors should
+     * override this and supply their own.
+     *
+     * <p>Subclasses could override this method to turn null.
      */
+    @Nullable
     public Editable getEditable() {
         if (mEditable == null) {
             mEditable = Editable.Factory.getInstance().newEditable("");
@@ -148,16 +173,14 @@
         return mEditable;
     }
 
-    /**
-     * Default implementation does nothing.
-     */
+    /** Default implementation does nothing. */
+    @Override
     public boolean beginBatchEdit() {
         return false;
     }
 
-    /**
-     * Default implementation does nothing.
-     */
+    /** Default implementation does nothing. */
+    @Override
     public boolean endBatchEdit() {
         return false;
     }
@@ -165,29 +188,29 @@
     /**
      * Called after only the composing region is modified (so it isn't called if the text also
      * changes).
-     * <p>
-     * Default implementation does nothing.
+     *
+     * <p>Default implementation does nothing.
      *
      * @hide
      */
-    public void endComposingRegionEditInternal() {
-    }
+    public void endComposingRegionEditInternal() {}
 
     /**
-     * Default implementation calls {@link #finishComposingText()} and
-     * {@code setImeConsumesInput(false)}.
+     * Default implementation calls {@link #finishComposingText()} and {@code
+     * setImeConsumesInput(false)}.
      */
     @CallSuper
+    @Override
     public void closeConnection() {
         finishComposingText();
         setImeConsumesInput(false);
     }
 
     /**
-     * Default implementation uses
-     * {@link MetaKeyKeyListener#clearMetaKeyState(long, int)
+     * Default implementation uses {@link MetaKeyKeyListener#clearMetaKeyState(long, int)
      * MetaKeyKeyListener.clearMetaKeyState(long, int)} to clear the state.
      */
+    @Override
     public boolean clearMetaKeyStates(int states) {
         final Editable content = getEditable();
         if (content == null) return false;
@@ -195,25 +218,24 @@
         return true;
     }
 
-    /**
-     * Default implementation does nothing and returns false.
-     */
+    /** Default implementation does nothing and returns false. */
+    @Override
     public boolean commitCompletion(CompletionInfo text) {
         return false;
     }
 
-    /**
-     * Default implementation does nothing and returns false.
-     */
+    /** Default implementation does nothing and returns false. */
+    @Override
     public boolean commitCorrection(CorrectionInfo correctionInfo) {
         return false;
     }
 
     /**
-     * Default implementation replaces any existing composing text with
-     * the given text.  In addition, only if fallback mode, a key event is
-     * sent for the new text and the current editable buffer cleared.
+     * Default implementation replaces any existing composing text with the given text. In addition,
+     * only if fallback mode, a key event is sent for the new text and the current editable buffer
+     * cleared.
      */
+    @Override
     public boolean commitText(CharSequence text, int newCursorPosition) {
         if (DEBUG) Log.v(TAG, "commitText " + text);
         replaceText(text, newCursorPosition, false);
@@ -226,21 +248,19 @@
      * editable text.
      *
      * @param beforeLength The number of characters before the cursor to be deleted, in code unit.
-     *        If this is greater than the number of existing characters between the beginning of the
-     *        text and the cursor, then this method does not fail but deletes all the characters in
-     *        that range.
-     * @param afterLength The number of characters after the cursor to be deleted, in code unit.
-     *        If this is greater than the number of existing characters between the cursor and
-     *        the end of the text, then this method does not fail but deletes all the characters in
-     *        that range.
-     *
-     * @return {@code true} when selected text is deleted, {@code false} when either the
-     *         selection is invalid or not yet attached (i.e. selection start or end is -1),
-     *         or the editable text is {@code null}.
+     *     If this is greater than the number of existing characters between the beginning of the
+     *     text and the cursor, then this method does not fail but deletes all the characters in
+     *     that range.
+     * @param afterLength The number of characters after the cursor to be deleted, in code unit. If
+     *     this is greater than the number of existing characters between the cursor and the end of
+     *     the text, then this method does not fail but deletes all the characters in that range.
+     * @return {@code true} when selected text is deleted, {@code false} when either the selection
+     *     is invalid or not yet attached (i.e. selection start or end is -1), or the editable text
+     *     is {@code null}.
      */
+    @Override
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
-        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
-                + " / " + afterLength);
+        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength + " / " + afterLength);
         final Editable content = getEditable();
         if (content == null) return false;
 
@@ -389,7 +409,7 @@
                 continue;
             }
             if (java.lang.Character.isLowSurrogate(c)) {
-                return INVALID_INDEX;  // A invalid surrogate pair is found.
+                return INVALID_INDEX; // A invalid surrogate pair is found.
             }
             waitingLowSurrogate = true;
             ++currentIndex;
@@ -399,18 +419,18 @@
     /**
      * The default implementation performs the deletion around the current selection position of the
      * editable text.
+     *
      * @param beforeLength The number of characters before the cursor to be deleted, in code points.
-     *        If this is greater than the number of existing characters between the beginning of the
-     *        text and the cursor, then this method does not fail but deletes all the characters in
-     *        that range.
+     *     If this is greater than the number of existing characters between the beginning of the
+     *     text and the cursor, then this method does not fail but deletes all the characters in
+     *     that range.
      * @param afterLength The number of characters after the cursor to be deleted, in code points.
-     *        If this is greater than the number of existing characters between the cursor and
-     *        the end of the text, then this method does not fail but deletes all the characters in
-     *        that range.
+     *     If this is greater than the number of existing characters between the cursor and the end
+     *     of the text, then this method does not fail but deletes all the characters in that range.
      */
+    @Override
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
-        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
-                + " / " + afterLength);
+        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength + " / " + afterLength);
         final Editable content = getEditable();
         if (content == null) return false;
 
@@ -466,10 +486,11 @@
     }
 
     /**
-     * The default implementation removes the composing state from the
-     * current editable text.  In addition, only if fallback mode, a key event is
-     * sent for the new text and the current editable buffer cleared.
+     * The default implementation removes the composing state from the current editable text. In
+     * addition, only if fallback mode, a key event is sent for the new text and the current
+     * editable buffer cleared.
      */
+    @Override
     public boolean finishComposingText() {
         if (DEBUG) Log.v(TAG, "finishComposingText");
         final Editable content = getEditable();
@@ -485,10 +506,11 @@
     }
 
     /**
-     * The default implementation uses TextUtils.getCapsMode to get the
-     * cursor caps mode for the current selection position in the editable
-     * text, unless in fallback mode in which case 0 is always returned.
+     * The default implementation uses TextUtils.getCapsMode to get the cursor caps mode for the
+     * current selection position in the editable text, unless in fallback mode in which case 0 is
+     * always returned.
      */
+    @Override
     public int getCursorCapsMode(int reqModes) {
         if (mFallbackMode) return 0;
 
@@ -507,17 +529,18 @@
         return TextUtils.getCapsMode(content, a, reqModes);
     }
 
-    /**
-     * The default implementation always returns null.
-     */
+    /** The default implementation always returns null. */
+    @Override
+    @Nullable
     public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         return null;
     }
 
     /**
-     * The default implementation returns the given amount of text from the
-     * current cursor position in the buffer.
+     * The default implementation returns the given amount of text from the current cursor position
+     * in the buffer.
      */
+    @Override
     @Nullable
     public CharSequence getTextBeforeCursor(@IntRange(from = 0) int length, int flags) {
         Preconditions.checkArgumentNonnegative(length);
@@ -549,9 +572,10 @@
     }
 
     /**
-     * The default implementation returns the text currently selected, or null if none is
-     * selected.
+     * The default implementation returns the text currently selected, or null if none is selected.
      */
+    @Override
+    @Nullable
     public CharSequence getSelectedText(int flags) {
         final Editable content = getEditable();
         if (content == null) return null;
@@ -574,9 +598,10 @@
     }
 
     /**
-     * The default implementation returns the given amount of text from the
-     * current cursor position in the buffer.
+     * The default implementation returns the given amount of text from the current cursor position
+     * in the buffer.
      */
+    @Override
     @Nullable
     public CharSequence getTextAfterCursor(@IntRange(from = 0) int length, int flags) {
         Preconditions.checkArgumentNonnegative(length);
@@ -602,7 +627,6 @@
             length = content.length() - b;
         }
 
-
         if ((flags&GET_TEXT_WITH_STYLES) != 0) {
             return content.subSequence(b, b + length);
         }
@@ -613,9 +637,10 @@
      * The default implementation returns the given amount of text around the current cursor
      * position in the buffer.
      */
+    @Override
     @Nullable
     public SurroundingText getSurroundingText(
-            @IntRange(from = 0) int beforeLength, @IntRange(from = 0)  int afterLength, int flags) {
+            @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength, int flags) {
         Preconditions.checkArgumentNonnegative(beforeLength);
         Preconditions.checkArgumentNonnegative(afterLength);
 
@@ -659,60 +684,75 @@
                 surroundingText, selStart - startPos, selEnd - startPos, startPos);
     }
 
-    /**
-     * The default implementation turns this into the enter key.
-     */
+    /** The default implementation turns this into the enter key. */
+    @Override
     public boolean performEditorAction(int actionCode) {
         long eventTime = SystemClock.uptimeMillis();
-        sendKeyEvent(new KeyEvent(eventTime, eventTime,
-                KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
-                | KeyEvent.FLAG_EDITOR_ACTION));
-        sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
-                KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
-                | KeyEvent.FLAG_EDITOR_ACTION));
+        sendKeyEvent(
+                new KeyEvent(
+                        eventTime,
+                        eventTime,
+                        KeyEvent.ACTION_DOWN,
+                        KeyEvent.KEYCODE_ENTER,
+                        0,
+                        0,
+                        KeyCharacterMap.VIRTUAL_KEYBOARD,
+                        0,
+                        KeyEvent.FLAG_SOFT_KEYBOARD
+                                | KeyEvent.FLAG_KEEP_TOUCH_MODE
+                                | KeyEvent.FLAG_EDITOR_ACTION));
+        sendKeyEvent(
+                new KeyEvent(
+                        SystemClock.uptimeMillis(),
+                        eventTime,
+                        KeyEvent.ACTION_UP,
+                        KeyEvent.KEYCODE_ENTER,
+                        0,
+                        0,
+                        KeyCharacterMap.VIRTUAL_KEYBOARD,
+                        0,
+                        KeyEvent.FLAG_SOFT_KEYBOARD
+                                | KeyEvent.FLAG_KEEP_TOUCH_MODE
+                                | KeyEvent.FLAG_EDITOR_ACTION));
         return true;
     }
 
-    /**
-     * The default implementation does nothing.
-     */
+    /** The default implementation does nothing. */
+    @Override
     public boolean performContextMenuAction(int id) {
         return false;
     }
 
-    /**
-     * The default implementation does nothing.
-     */
+    /** The default implementation does nothing. */
+    @Override
     public boolean performPrivateCommand(String action, Bundle data) {
         return false;
     }
 
-    /**
-     * The default implementation does nothing.
-     */
+    /** The default implementation does nothing. */
+    @Override
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         return false;
     }
 
+    @Override
+    @Nullable
     public Handler getHandler() {
         return null;
     }
 
     /**
-     * The default implementation places the given text into the editable,
-     * replacing any existing composing text.  The new text is marked as
-     * in a composing state with the composing style.
+     * The default implementation places the given text into the editable, replacing any existing
+     * composing text. The new text is marked as in a composing state with the composing style.
      */
+    @Override
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         if (DEBUG) Log.v(TAG, "setComposingText " + text);
         replaceText(text, newCursorPosition, true);
         return true;
     }
 
+    @Override
     public boolean setComposingRegion(int start, int end) {
         final Editable content = getEditable();
         if (content != null) {
@@ -735,7 +775,10 @@
             ensureDefaultComposingSpans();
             if (mDefaultComposingSpans != null) {
                 for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
-                    content.setSpan(mDefaultComposingSpans[i], a, b,
+                    content.setSpan(
+                            mDefaultComposingSpans[i],
+                            a,
+                            b,
                             Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
                 }
             }
@@ -751,10 +794,8 @@
         return true;
     }
 
-    /**
-     * The default implementation changes the selection position in the
-     * current editable text.
-     */
+    /** The default implementation changes the selection position in the current editable text. */
+    @Override
     public boolean setSelection(int start, int end) {
         if (DEBUG) Log.v(TAG, "setSelection " + start + ", " + end);
         final Editable content = getEditable();
@@ -779,17 +820,17 @@
     }
 
     /**
-     * Provides standard implementation for sending a key event to the window
-     * attached to the input connection's view.
+     * Provides standard implementation for sending a key event to the window attached to the input
+     * connection's view.
      */
+    @Override
     public boolean sendKeyEvent(KeyEvent event) {
         mIMM.dispatchKeyEventFromInputMethod(mTargetView, event);
         return false;
     }
 
-    /**
-     * Updates InputMethodManager with the current fullscreen mode.
-     */
+    /** Updates InputMethodManager with the current fullscreen mode. */
+    @Override
     public boolean reportFullscreenMode(boolean enabled) {
         return true;
     }
@@ -934,8 +975,7 @@
             newCursorPosition += a;
         }
         if (newCursorPosition < 0) newCursorPosition = 0;
-        if (newCursorPosition > content.length())
-            newCursorPosition = content.length();
+        if (newCursorPosition > content.length()) newCursorPosition = content.length();
         Selection.setSelection(content, newCursorPosition);
 
         content.replace(a, b, text);
@@ -950,11 +990,16 @@
     }
 
     /**
-     * Default implementation which invokes {@link View#performReceiveContent} on the target
-     * view if the view {@link View#getReceiveContentMimeTypes allows} content insertion;
-     * otherwise returns false without any side effects.
+     * Default implementation which invokes {@link View#performReceiveContent} on the target view if
+     * the view {@link View#getReceiveContentMimeTypes allows} content insertion; otherwise returns
+     * false without any side effects.
      */
+    @Override
     public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+        if (mTargetView == null) {
+            return false;
+        }
+
         ClipDescription description = inputContentInfo.getDescription();
         if (mTargetView.getReceiveContentMimeTypes() == null) {
             if (DEBUG) {
diff --git a/core/java/android/view/inputmethod/DeleteGesture.java b/core/java/android/view/inputmethod/DeleteGesture.java
index 1395578..c88158f 100644
--- a/core/java/android/view/inputmethod/DeleteGesture.java
+++ b/core/java/android/view/inputmethod/DeleteGesture.java
@@ -27,9 +27,11 @@
 import java.util.Objects;
 
 /**
- * A sub-class of {@link HandwritingGesture} for deleting an area of text.
+ * A sub-class of {@link HandwritingGesture} for deleting an area of text using single rectangle.
  * This class holds the information required for deletion of text in
  * toolkit widgets like {@link TextView}.
+ * <p>Note: This deletes all text <em>within</em> the given area. To delete a range <em>between</em>
+ * two areas, use {@link DeleteRangeGesture}.</p>
  */
 public final class DeleteGesture extends HandwritingGesture implements Parcelable {
 
@@ -64,7 +66,6 @@
      * Returns the deletion area {@link RectF} in screen coordinates.
      *
      * Getter for deletion area set with {@link DeleteGesture.Builder#setDeletionArea(RectF)}.
-     * {@code null} if area was not set.
      */
     @NonNull
     public RectF getDeletionArea() {
@@ -145,7 +146,8 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final @android.annotation.NonNull Creator<DeleteGesture> CREATOR =
+    @NonNull
+    public static final Creator<DeleteGesture> CREATOR =
             new Creator<DeleteGesture>() {
         @Override
         public DeleteGesture createFromParcel(Parcel source) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/core/java/android/view/inputmethod/DeleteRangeGesture.aidl
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to core/java/android/view/inputmethod/DeleteRangeGesture.aidl
index 1de740a..0ae8899 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/core/java/android/view/inputmethod/DeleteRangeGesture.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package android.view.inputmethod;
 
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+parcelable DeleteRangeGesture;
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/DeleteRangeGesture.java b/core/java/android/view/inputmethod/DeleteRangeGesture.java
new file mode 100644
index 0000000..53b4209
--- /dev/null
+++ b/core/java/android/view/inputmethod/DeleteRangeGesture.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.TextView;
+
+import java.util.Objects;
+
+/**
+ * A subclass of {@link HandwritingGesture} for deleting a range of text by defining start and end
+ * rectangles. This can be useful when the range cannot be defined with a single rectangle.
+ * This class holds the information required for deletion of text in
+ * toolkit widgets like {@link TextView}.
+ * <p>Note: this deletes text within a range <em>between</em> two given areas. To delete all text
+ * <em>within</em> a single area, use {@link DeleteGesture}.</p>
+ */
+public final class DeleteRangeGesture extends HandwritingGesture implements Parcelable {
+
+    private @Granularity int mGranularity;
+    private RectF mStartArea;
+    private RectF mEndArea;
+
+    private DeleteRangeGesture(
+            int granularity, RectF startArea, RectF endArea, String fallbackText) {
+        mType = GESTURE_TYPE_DELETE_RANGE;
+        mStartArea = startArea;
+        mEndArea = endArea;
+        mGranularity = granularity;
+        mFallbackText = fallbackText;
+    }
+
+    private DeleteRangeGesture(@NonNull Parcel source) {
+        mType = GESTURE_TYPE_DELETE_RANGE;
+        mFallbackText = source.readString8();
+        mGranularity = source.readInt();
+        mStartArea = source.readTypedObject(RectF.CREATOR);
+        mEndArea = source.readTypedObject(RectF.CREATOR);
+    }
+
+    /**
+     * Returns Granular level on which text should be operated.
+     * @see #GRANULARITY_CHARACTER
+     * @see #GRANULARITY_WORD
+     */
+    @Granularity
+    public int getGranularity() {
+        return mGranularity;
+    }
+
+    /**
+     * Returns the Deletion start area {@link RectF} in screen coordinates.
+     *
+     * Getter for deletion area set with {@link Builder#setDeletionStartArea(RectF)}.
+     */
+    @NonNull
+    public RectF getDeletionStartArea() {
+        return mStartArea;
+    }
+
+    /**
+     * Returns the Deletion end area {@link RectF} in screen coordinates.
+     *
+     * Getter for deletion area set with {@link Builder#setDeletionEndArea(RectF)}.
+     */
+    @NonNull
+    public RectF getDeletionEndArea() {
+        return mEndArea;
+    }
+
+    /**
+     * Builder for {@link DeleteRangeGesture}. This class is not designed to be thread-safe.
+     */
+    public static final class Builder {
+        private int mGranularity;
+        private RectF mStartArea;
+        private RectF mEndArea;
+        private String mFallbackText;
+
+        /**
+         * Define text deletion granularity. Intersecting words/characters will be
+         * included in the operation.
+         * @param granularity {@link HandwritingGesture#GRANULARITY_WORD} or
+         * {@link HandwritingGesture#GRANULARITY_CHARACTER}.
+         * @return {@link Builder}.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setGranularity(@Granularity int granularity) {
+            mGranularity = granularity;
+            return this;
+        }
+
+        /**
+         * Set rectangular single/multiline start of text deletion area intersecting with text.
+         *
+         * The resulting deletion is performed from the start of first word/character in the start
+         * rectangle to the end of the last word/character in the end rectangle
+         * {@link #setDeletionEndArea(RectF)}.
+         * <br/>
+         * <img src="{@docRoot}reference/android/images/input_method/stylus_handwriting
+         * /delete_range_gesture_rects.png"
+         * height="300" alt="Deletion strategy using two rectangles"/>
+         *  <br/>
+         *
+         * Intersection is determined using
+         * {@link #setGranularity(int)}. e.g. {@link HandwritingGesture#GRANULARITY_WORD} includes
+         * all the words with their width/height center included in the deletion rectangle.
+         * @param startArea {@link RectF} (in screen coordinates) for start of deletion. This
+         * rectangle belongs to first line where deletion should start.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setDeletionStartArea(@NonNull RectF startArea) {
+            mStartArea = startArea;
+            return this;
+        }
+
+        /**
+         * Set rectangular single/multiline end of text deletion area intersecting with text.
+         *
+         * The resulting deletion is performed from the start of first word/character in the start
+         * rectangle {@link #setDeletionStartArea(RectF)} to the end of the last word/character in
+         * the end rectangle.
+         * <br/>
+         * <img src="{@docRoot}reference/android/images/input_method/stylus_handwriting
+         * /delete_range_gesture_rects.png"
+         * height="300" alt="Deletion strategy using two rectangles"/>
+         *
+         * Intersection is determined using
+         * {@link #setGranularity(int)}. e.g. {@link HandwritingGesture#GRANULARITY_WORD} includes
+         * all the words with their width/height center included in the deletion rectangle.
+         * @param endArea {@link RectF} (in screen coordinates) for start of deletion. This
+         * rectangle belongs to the last line where deletion should end.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setDeletionEndArea(@NonNull RectF endArea) {
+            mEndArea = endArea;
+            return this;
+        }
+
+        /**
+         * Set fallback text that will be committed at current cursor position if there is no
+         * applicable text beneath the area of gesture.
+         * @param fallbackText text to set
+         */
+        @NonNull
+        public Builder setFallbackText(@Nullable String fallbackText) {
+            mFallbackText = fallbackText;
+            return this;
+        }
+
+        /**
+         * @return {@link DeleteRangeGesture} using parameters in this
+         * {@link DeleteRangeGesture.Builder}.
+         * @throws IllegalArgumentException if one or more positional parameters are not specified.
+         */
+        @NonNull
+        public DeleteRangeGesture build() {
+            if (mStartArea == null || mStartArea.isEmpty() || mEndArea == null
+                    || mEndArea.isEmpty()) {
+                throw new IllegalArgumentException("Deletion area must be set.");
+            }
+            if (mGranularity <= GRANULARITY_UNDEFINED) {
+                throw new IllegalArgumentException("Deletion granularity must be set.");
+            }
+            return new DeleteRangeGesture(mGranularity, mStartArea, mEndArea, mFallbackText);
+        }
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    @NonNull
+    public static final Creator<DeleteRangeGesture> CREATOR =
+            new Creator<DeleteRangeGesture>() {
+                @Override
+                public DeleteRangeGesture createFromParcel(Parcel source) {
+                    return new DeleteRangeGesture(source);
+                }
+
+                @Override
+                public DeleteRangeGesture[] newArray(int size) {
+                    return new DeleteRangeGesture[size];
+                }
+            };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mGranularity, mStartArea, mEndArea, mFallbackText);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof DeleteRangeGesture)) return false;
+
+        DeleteRangeGesture that = (DeleteRangeGesture) o;
+
+        if (mGranularity != that.mGranularity) return false;
+        if (!Objects.equals(mFallbackText, that.mFallbackText)) return false;
+        if (!Objects.equals(mStartArea, that.mStartArea)) return false;
+        return Objects.equals(mEndArea, that.mEndArea);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mFallbackText);
+        dest.writeInt(mGranularity);
+        dest.writeTypedObject(mStartArea, flags);
+        dest.writeTypedObject(mEndArea, flags);
+    }
+}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 36b0334..4a79ba6 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -557,10 +557,18 @@
             Objects.requireNonNull(gesture);
             if (gesture.equals(SelectGesture.class)) {
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_SELECT;
+            } else if (gesture.equals(SelectRangeGesture.class)) {
+                supportedTypes |= HandwritingGesture.GESTURE_TYPE_SELECT_RANGE;
             } else if (gesture.equals(InsertGesture.class)) {
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_INSERT;
             } else if (gesture.equals(DeleteGesture.class)) {
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_DELETE;
+            } else if (gesture.equals(DeleteRangeGesture.class)) {
+                supportedTypes |= HandwritingGesture.GESTURE_TYPE_DELETE_RANGE;
+            } else if (gesture.equals(RemoveSpaceGesture.class)) {
+                supportedTypes |= HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE;
+            } else if (gesture.equals(JoinOrSplitGesture.class)) {
+                supportedTypes |= HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT;
             } else {
                 throw new IllegalArgumentException("Unknown gesture type: " + gesture);
             }
@@ -595,6 +603,14 @@
                 == HandwritingGesture.GESTURE_TYPE_DELETE) {
             list.add(DeleteGesture.class);
         }
+        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE)
+                == HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) {
+            list.add(RemoveSpaceGesture.class);
+        }
+        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT)
+                == HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT) {
+            list.add(JoinOrSplitGesture.class);
+        }
         return list;
     }
 
diff --git a/core/java/android/view/inputmethod/HandwritingGesture.java b/core/java/android/view/inputmethod/HandwritingGesture.java
index a659333..07b1e1f 100644
--- a/core/java/android/view/inputmethod/HandwritingGesture.java
+++ b/core/java/android/view/inputmethod/HandwritingGesture.java
@@ -25,6 +25,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.function.IntConsumer;
 
@@ -99,15 +100,35 @@
      */
     public static final int GESTURE_TYPE_DELETE = 1 << 2;
 
+    /** Gesture of type {@link RemoveSpaceGesture} to remove whitespace from text. */
+    public static final int GESTURE_TYPE_REMOVE_SPACE = 1 << 3;
+
+    /** Gesture of type {@link JoinOrSplitGesture} to join or split text. */
+    public static final int GESTURE_TYPE_JOIN_OR_SPLIT = 1 << 4;
+
+    /**
+     * Gesture of type {@link SelectRangeGesture} to select range of text.
+     */
+    public static final int GESTURE_TYPE_SELECT_RANGE = 1 << 5;
+
+    /**
+     * Gesture of type {@link DeleteRangeGesture} to delete range of text.
+     */
+    public static final int GESTURE_TYPE_DELETE_RANGE = 1 << 6;
+
     /**
      * Type of gesture like {@link #GESTURE_TYPE_SELECT}, {@link #GESTURE_TYPE_INSERT},
      * or {@link #GESTURE_TYPE_DELETE}.
      */
     @IntDef(prefix = {"GESTURE_TYPE_"}, value = {
-                GESTURE_TYPE_NONE,
-                GESTURE_TYPE_SELECT,
-                GESTURE_TYPE_INSERT,
-                GESTURE_TYPE_DELETE})
+            GESTURE_TYPE_NONE,
+            GESTURE_TYPE_SELECT,
+            GESTURE_TYPE_SELECT_RANGE,
+            GESTURE_TYPE_INSERT,
+            GESTURE_TYPE_DELETE,
+            GESTURE_TYPE_DELETE_RANGE,
+            GESTURE_TYPE_REMOVE_SPACE,
+            GESTURE_TYPE_JOIN_OR_SPLIT})
     @Retention(RetentionPolicy.SOURCE)
     @interface GestureType{}
 
@@ -115,13 +136,17 @@
      * Flags which can be any combination of {@link #GESTURE_TYPE_SELECT},
      * {@link #GESTURE_TYPE_INSERT}, or {@link #GESTURE_TYPE_DELETE}.
      * {@link GestureTypeFlags} can be used by editors to declare what gestures are supported
-     *  and report them in {@link EditorInfo#setSupportedHandwritingGestureTypes(int)}.
+     *  and report them in {@link EditorInfo#setSupportedHandwritingGestures(List)}.
      * @hide
      */
     @IntDef(flag = true, prefix = {"GESTURE_TYPE_"}, value = {
             GESTURE_TYPE_SELECT,
+            GESTURE_TYPE_SELECT_RANGE,
             GESTURE_TYPE_INSERT,
-            GESTURE_TYPE_DELETE})
+            GESTURE_TYPE_DELETE,
+            GESTURE_TYPE_DELETE_RANGE,
+            GESTURE_TYPE_REMOVE_SPACE,
+            GESTURE_TYPE_JOIN_OR_SPLIT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface GestureTypeFlags{}
 
@@ -130,7 +155,7 @@
     /**
      * Returns the gesture type {@link GestureType}.
      * {@link GestureType} can be used by editors to declare what gestures are supported and report
-     * them in {@link EditorInfo#setSupportedHandwritingGestureTypes(int)}.
+     * them in {@link EditorInfo#setSupportedHandwritingGestures(List)}.
      * @hide
      */
     @TestApi
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 9acd1af..0c7c163 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1771,7 +1771,7 @@
         if (getServedViewLocked() != null) {
             if (DEBUG) {
                 Log.v(TAG, "FINISH INPUT: mServedView="
-                        + dumpViewInfo(getServedViewLocked()));
+                        + InputMethodDebug.dumpViewInfo(getServedViewLocked()));
             }
             setServedViewLocked(null);
             mCompletions = null;
@@ -2304,7 +2304,7 @@
 
             // Make sure we have a window token for the served view.
             if (DEBUG) {
-                Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) +
+                Log.v(TAG, "Starting input: view=" + InputMethodDebug.dumpViewInfo(view) +
                         " reason=" + InputMethodDebug.startInputReasonToString(startInputReason));
             }
             if (view == null) {
@@ -2375,9 +2375,9 @@
             final View servedView = getServedViewLocked();
             if (servedView != view || !mServedConnecting) {
                 // Something else happened, so abort.
-                if (DEBUG) Log.v(TAG,
-                        "Starting input: finished by someone else. view=" + dumpViewInfo(view)
-                        + " servedView=" + dumpViewInfo(servedView)
+                if (DEBUG) Log.v(TAG, "Starting input: finished by someone else."
+                        + " view=" + InputMethodDebug.dumpViewInfo(view)
+                        + " servedView=" + InputMethodDebug.dumpViewInfo(servedView)
                         + " mServedConnecting=" + mServedConnecting);
                 if (mServedInputConnection != null && startInputReason == BOUND_TO_IMMS) {
                     // This is not an error. Once IME binds (MSG_BIND), InputConnection is fully
@@ -2437,8 +2437,8 @@
             mServedInputConnection = servedInputConnection;
 
             if (DEBUG) {
-                Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
-                        + ic + " editorInfo=" + editorInfo + " startInputFlags="
+                Log.v(TAG, "START INPUT: view=" + InputMethodDebug.dumpViewInfo(view)
+                        + " ic=" + ic + " editorInfo=" + editorInfo + " startInputFlags="
                         + InputMethodDebug.startInputFlagsToString(startInputFlags));
             }
 
@@ -3774,23 +3774,6 @@
         return mCurBindState != null ? mCurBindState.mBindSequence : -1;
     }
 
-    private static String dumpViewInfo(@Nullable final View view) {
-        if (view == null) {
-            return "null";
-        }
-        final StringBuilder sb = new StringBuilder();
-        sb.append(view);
-        sb.append(",focus=" + view.hasFocus());
-        sb.append(",windowFocus=" + view.hasWindowFocus());
-        sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
-        sb.append(",window=" + view.getWindowToken());
-        sb.append(",displayId=" + view.getContext().getDisplayId());
-        sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
-        sb.append(",hasImeFocus=" + view.hasImeFocus());
-
-        return sb.toString();
-    }
-
     /**
      * Checks the args to see if a proto-based ime dump was requested and writes the client side
      * ime dump to the given {@link FileDescriptor}.
diff --git a/core/java/android/view/inputmethod/InsertGesture.java b/core/java/android/view/inputmethod/InsertGesture.java
index cffdf35..8b8359e 100644
--- a/core/java/android/view/inputmethod/InsertGesture.java
+++ b/core/java/android/view/inputmethod/InsertGesture.java
@@ -124,7 +124,8 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final @android.annotation.NonNull Creator<InsertGesture> CREATOR =
+    @NonNull
+    public static final Creator<InsertGesture> CREATOR =
             new Creator<InsertGesture>() {
         @Override
         public InsertGesture createFromParcel(Parcel source) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
index 1de740a..e339b55 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package android.view.inputmethod;
 
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+parcelable JoinOrSplitGesture;
diff --git a/core/java/android/view/inputmethod/JoinOrSplitGesture.java b/core/java/android/view/inputmethod/JoinOrSplitGesture.java
new file mode 100644
index 0000000..2fa8063
--- /dev/null
+++ b/core/java/android/view/inputmethod/JoinOrSplitGesture.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.PointF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A subclass of {@link HandwritingGesture} for deleting or inserting whitespace in text. If the
+ * gesture is drawn over whitespace, then the whitespace will be deleted. Otherwise, a space will be
+ * inserted.
+ */
+public final class JoinOrSplitGesture extends HandwritingGesture implements Parcelable {
+
+    private final PointF mPoint;
+
+    private JoinOrSplitGesture(PointF point, String fallbackText) {
+        mType = GESTURE_TYPE_JOIN_OR_SPLIT;
+        mPoint = point;
+        mFallbackText = fallbackText;
+    }
+
+    private JoinOrSplitGesture(@NonNull Parcel source) {
+        mType = GESTURE_TYPE_JOIN_OR_SPLIT;
+        mPoint = source.readTypedObject(PointF.CREATOR);
+        mFallbackText = source.readString8();
+    }
+
+    /**
+     * Returns the gesture point in screen coordinates set with {@link Builder#setJoinOrSplitPoint}.
+     */
+    @NonNull
+    public PointF getJoinOrSplitPoint() {
+        return mPoint;
+    }
+
+    /** Builder for {@link JoinOrSplitGesture}. This class is not designed to be thread-safe. */
+    public static final class Builder {
+        private PointF mPoint;
+        private String mFallbackText;
+
+        /**
+         * Sets the point to apply the join or split operation in screen coordinates.
+         *
+         * <p>If the text cursor position closest to the point is inside or on the boundary of
+         * whitespace, then the whitespace will be deleted, joining the text on either side of the
+         * whitespace. If there are multiple consecutive whitespace characters, then the entire
+         * whitespace block will be deleted.
+         *
+         * <p>Otherwise, if the text cursor position closest to the point is not touching
+         * whitespace, then a space will be inserted at that position.
+         */
+        @NonNull
+        public Builder setJoinOrSplitPoint(@NonNull PointF point) {
+            mPoint = point;
+            return this;
+        }
+
+        /**
+         * Sets fallback text that will be committed at current cursor position if there is no
+         * applicable text beneath the gesture point.
+         */
+        @NonNull
+        public Builder setFallbackText(@Nullable String fallbackText) {
+            mFallbackText = fallbackText;
+            return this;
+        }
+
+        /**
+         * @return {@link JoinOrSplitGesture} using parameters in this {@link Builder}.
+         * @throws IllegalArgumentException if one or more positional parameters are not specified.
+         */
+        @NonNull
+        public JoinOrSplitGesture build() {
+            if (mPoint == null) {
+                throw new IllegalArgumentException("Point must be set.");
+            }
+            return new JoinOrSplitGesture(mPoint, mFallbackText);
+        }
+    }
+
+    /** Used to make this class parcelable. */
+    @NonNull
+    public static final Parcelable.Creator<JoinOrSplitGesture> CREATOR =
+            new Parcelable.Creator<JoinOrSplitGesture>() {
+                @Override
+                public JoinOrSplitGesture createFromParcel(Parcel source) {
+                    return new JoinOrSplitGesture(source);
+                }
+
+                @Override
+                public JoinOrSplitGesture[] newArray(int size) {
+                    return new JoinOrSplitGesture[size];
+                }
+            };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPoint, mFallbackText);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof JoinOrSplitGesture)) return false;
+        JoinOrSplitGesture that = (JoinOrSplitGesture) o;
+        return Objects.equals(mPoint, that.mPoint)
+                && Objects.equals(mFallbackText, that.mFallbackText);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest {@link Parcel} to be written
+     * @param flags flags used for parceling
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mPoint, flags);
+        dest.writeString8(mFallbackText);
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
index 1de740a..7aab528 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package android.view.inputmethod;
 
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+parcelable RemoveSpaceGesture;
diff --git a/core/java/android/view/inputmethod/RemoveSpaceGesture.java b/core/java/android/view/inputmethod/RemoveSpaceGesture.java
new file mode 100644
index 0000000..936f259
--- /dev/null
+++ b/core/java/android/view/inputmethod/RemoveSpaceGesture.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.PointF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/** A subclass of {@link HandwritingGesture} for removing whitespace from text. */
+public final class RemoveSpaceGesture extends HandwritingGesture implements Parcelable {
+
+    private final PointF mStartPoint;
+    private final PointF mEndPoint;
+
+    private RemoveSpaceGesture(PointF startPoint, PointF endPoint, String fallbackText) {
+        mType = GESTURE_TYPE_REMOVE_SPACE;
+        mStartPoint = startPoint;
+        mEndPoint = endPoint;
+        mFallbackText = fallbackText;
+    }
+
+    private RemoveSpaceGesture(@NonNull Parcel source) {
+        mType = GESTURE_TYPE_REMOVE_SPACE;
+        mStartPoint = source.readTypedObject(PointF.CREATOR);
+        mEndPoint = source.readTypedObject(PointF.CREATOR);
+        mFallbackText = source.readString8();
+    }
+
+    /** Returns the start point in screen coordinates set with {@link Builder#setPoints}. */
+    @NonNull
+    public PointF getStartPoint() {
+        return mStartPoint;
+    }
+
+    /** Returns the end point in screen coordinates set with {@link Builder#setPoints}. */
+    @NonNull
+    public PointF getEndPoint() {
+        return mEndPoint;
+    }
+
+    /** Builder for {@link RemoveSpaceGesture}. This class is not designed to be thread-safe. */
+    public static final class Builder {
+        private PointF mStartPoint;
+        private PointF mEndPoint;
+        private String mFallbackText;
+
+        /**
+         * Sets the start and end points in screen coordinates of the line to apply the remove space
+         * operation. All whitespace characters touched by the line joining the points will be
+         * deleted.
+         *
+         * <p>The operation will only be performed on a single line of text. If the start and end
+         * points are on different lines of text, the line will be adjusted to cover only the first
+         * line of text containing one of the points.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setPoints(@NonNull PointF startPoint, @NonNull PointF endPoint) {
+            mStartPoint = startPoint;
+            mEndPoint = endPoint;
+            return this;
+        }
+
+        /**
+         * Sets fallback text that will be committed at current cursor position if there is no
+         * whitespace beneath the gesture line.
+         */
+        @NonNull
+        public Builder setFallbackText(@Nullable String fallbackText) {
+            mFallbackText = fallbackText;
+            return this;
+        }
+
+        /**
+         * @return {@link RemoveSpaceGesture} using parameters in this {@link Builder}.
+         * @throws IllegalArgumentException if one or more positional parameters are not specified.
+         */
+        @NonNull
+        public RemoveSpaceGesture build() {
+            if (mStartPoint == null || mEndPoint == null) {
+                throw new IllegalArgumentException("Start and end points must be set.");
+            }
+            return new RemoveSpaceGesture(mStartPoint, mEndPoint, mFallbackText);
+        }
+    }
+
+    /** Used to make this class parcelable. */
+    @NonNull
+    public static final Parcelable.Creator<RemoveSpaceGesture> CREATOR =
+            new Parcelable.Creator<RemoveSpaceGesture>() {
+                @Override
+                public RemoveSpaceGesture createFromParcel(Parcel source) {
+                    return new RemoveSpaceGesture(source);
+                }
+
+                @Override
+                public RemoveSpaceGesture[] newArray(int size) {
+                    return new RemoveSpaceGesture[size];
+                }
+            };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStartPoint, mEndPoint, mFallbackText);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof RemoveSpaceGesture)) return false;
+        RemoveSpaceGesture that = (RemoveSpaceGesture) o;
+        return Objects.equals(mStartPoint, that.mStartPoint)
+                && Objects.equals(mEndPoint, that.mEndPoint)
+                && Objects.equals(mFallbackText, that.mFallbackText);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest {@link Parcel} to be written
+     * @param flags flags used for parceling
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mStartPoint, flags);
+        dest.writeTypedObject(mEndPoint, flags);
+        dest.writeString8(mFallbackText);
+    }
+}
diff --git a/core/java/android/view/inputmethod/SelectGesture.java b/core/java/android/view/inputmethod/SelectGesture.java
index 5b68517..6dc4ed2 100644
--- a/core/java/android/view/inputmethod/SelectGesture.java
+++ b/core/java/android/view/inputmethod/SelectGesture.java
@@ -27,9 +27,11 @@
 import java.util.Objects;
 
 /**
- * A sub-class of {@link HandwritingGesture} for selecting an area of text.
+ * A sub-class of {@link HandwritingGesture} for selecting an area of text using single rectangle.
  * This class holds the information required for selection of text in
  * toolkit widgets like {@link TextView}.
+ * <p>Note: This selects all text <em>within</em> the given area. To select a range <em>between</em>
+ * two areas, use {@link SelectRangeGesture}.</p>
  */
 public final class SelectGesture extends HandwritingGesture implements Parcelable {
 
@@ -63,8 +65,7 @@
     /**
      * Returns the Selection area {@link RectF} in screen coordinates.
      *
-     * Getter for selection area set with {@link Builder#setSelectionArea(RectF)}. {@code null}
-     * if area was not set.
+     * Getter for selection area set with {@link Builder#setSelectionArea(RectF)}.
      */
     @NonNull
     public RectF getSelectionArea() {
@@ -126,7 +127,7 @@
         }
 
         /**
-         * @return {@link SelectGesture} using parameters in this {@link InsertGesture.Builder}.
+         * @return {@link SelectGesture} using parameters in this {@link Builder}.
          * @throws IllegalArgumentException if one or more positional parameters are not specified.
          */
         @NonNull
@@ -144,7 +145,8 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final @android.annotation.NonNull Parcelable.Creator<SelectGesture> CREATOR =
+    @NonNull
+    public static final Parcelable.Creator<SelectGesture> CREATOR =
             new Parcelable.Creator<SelectGesture>() {
         @Override
         public SelectGesture createFromParcel(Parcel source) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/core/java/android/view/inputmethod/SelectRangeGesture.aidl
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to core/java/android/view/inputmethod/SelectRangeGesture.aidl
index 1de740a..a7bce0a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/core/java/android/view/inputmethod/SelectRangeGesture.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package android.view.inputmethod;
 
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+parcelable SelectRangeGesture;
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/SelectRangeGesture.java b/core/java/android/view/inputmethod/SelectRangeGesture.java
new file mode 100644
index 0000000..7cb6002
--- /dev/null
+++ b/core/java/android/view/inputmethod/SelectRangeGesture.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.TextView;
+
+import java.util.Objects;
+
+/**
+ * A subclass of {@link HandwritingGesture} for selecting a range of text by defining start and end
+ * rectangles. This can be useful when the range cannot be defined with a single rectangle.
+ * This class holds the information required for selection of text in
+ * toolkit widgets like {@link TextView}.
+ * <p>Note: this selects text within a range <em>between</em> two given areas. To select all text
+ * <em>within</em> a single area, use {@link SelectGesture}</p>
+ */
+public final class SelectRangeGesture extends HandwritingGesture implements Parcelable {
+
+    private @Granularity int mGranularity;
+    private RectF mStartArea;
+    private RectF mEndArea;
+
+    private SelectRangeGesture(
+            int granularity, RectF startArea, RectF endArea, String fallbackText) {
+        mType = GESTURE_TYPE_SELECT_RANGE;
+        mStartArea = startArea;
+        mEndArea = endArea;
+        mGranularity = granularity;
+        mFallbackText = fallbackText;
+    }
+
+    private SelectRangeGesture(@NonNull Parcel source) {
+        mType = GESTURE_TYPE_SELECT_RANGE;
+        mFallbackText = source.readString8();
+        mGranularity = source.readInt();
+        mStartArea = source.readTypedObject(RectF.CREATOR);
+        mEndArea = source.readTypedObject(RectF.CREATOR);
+    }
+
+    /**
+     * Returns Granular level on which text should be operated.
+     * @see #GRANULARITY_CHARACTER
+     * @see #GRANULARITY_WORD
+     */
+    @Granularity
+    public int getGranularity() {
+        return mGranularity;
+    }
+
+    /**
+     * Returns the Selection start area {@link RectF} in screen coordinates.
+     *
+     * Getter for selection area set with {@link Builder#setSelectionStartArea(RectF)}.
+     */
+    @NonNull
+    public RectF getSelectionStartArea() {
+        return mStartArea;
+    }
+
+    /**
+     * Returns the Selection end area {@link RectF} in screen coordinates.
+     *
+     * Getter for selection area set with {@link Builder#setSelectionEndArea(RectF)}.
+     */
+    @NonNull
+    public RectF getSelectionEndArea() {
+        return mEndArea;
+    }
+
+
+    /**
+     * Builder for {@link SelectRangeGesture}. This class is not designed to be thread-safe.
+     */
+    public static final class Builder {
+        private int mGranularity;
+        private RectF mStartArea;
+        private RectF mEndArea;
+        private String mFallbackText;
+
+        /**
+         * Define text selection granularity. Intersecting words/characters will be
+         * included in the operation.
+         * @param granularity {@link HandwritingGesture#GRANULARITY_WORD} or
+         * {@link HandwritingGesture#GRANULARITY_CHARACTER}.
+         * @return {@link Builder}.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setGranularity(@HandwritingGesture.Granularity int granularity) {
+            mGranularity = granularity;
+            return this;
+        }
+
+        /**
+         * Set rectangular single/multiline start of text selection area intersecting with text.
+         *
+         * The resulting selection is performed from the start of first word/character in the start
+         * rectangle to the end of the last word/character in the end rectangle
+         * {@link #setSelectionEndArea(RectF)}.
+         * <br/>
+         * <img src="{@docRoot}reference/android/images/input_method/stylus_handwriting
+         * /select_range_gesture_rects.png"
+         * height="300" alt="Selection strategy using two rectangles"/>
+         *  <br/>
+         *
+         * Intersection is determined using
+         * {@link #setGranularity(int)}. e.g. {@link HandwritingGesture#GRANULARITY_WORD} includes
+         * all the words with their width/height center included in the selection rectangle.
+         * @param startArea {@link RectF} (in screen coordinates) for start of selection. This
+         * rectangle belongs to first line where selection should start.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setSelectionStartArea(@NonNull RectF startArea) {
+            mStartArea = startArea;
+            return this;
+        }
+
+        /**
+         * Set rectangular single/multiline end of text selection area intersecting with text.
+         *
+         * The resulting selection is performed from the start of first word/character in the start
+         * rectangle {@link #setSelectionStartArea(RectF)} to the end of the last word/character in
+         * the end rectangle.
+         * <br/>
+         * <img src="{@docRoot}reference/android/images/input_method/stylus_handwriting
+         * /select_range_gesture_rects.png"
+         * height="300" alt="Selection strategy using two rectangles"/>
+         *  <br/>
+         *
+         * The selection includes the first word/character in the rectangle, the last
+         * word/character in the rectangle, and everything in between even if it's not in the
+         * rectangle.
+         *
+         * Intersection is determined using
+         * {@link #setGranularity(int)}. e.g. {@link HandwritingGesture#GRANULARITY_WORD} includes
+         * all the words with their width/height center included in the selection rectangle.
+         * @param endArea {@link RectF} (in screen coordinates) for start of selection. This
+         * rectangle belongs to the last line where selection should end.
+         */
+        @NonNull
+        @SuppressLint("MissingGetterMatchingBuilder")
+        public Builder setSelectionEndArea(@NonNull RectF endArea) {
+            mEndArea = endArea;
+            return this;
+        }
+
+        /**
+         * Set fallback text that will be committed at current cursor position if there is no
+         * applicable text beneath the area of gesture.
+         * @param fallbackText text to set
+         */
+        @NonNull
+        public Builder setFallbackText(@Nullable String fallbackText) {
+            mFallbackText = fallbackText;
+            return this;
+        }
+
+        /**
+         * @return {@link SelectRangeGesture} using parameters in this
+         * {@link SelectRangeGesture.Builder}.
+         * @throws IllegalArgumentException if one or more positional parameters are not specified.
+         */
+        @NonNull
+        public SelectRangeGesture build() {
+            if (mStartArea == null || mStartArea.isEmpty() || mEndArea == null
+                    || mEndArea.isEmpty()) {
+                throw new IllegalArgumentException("Selection area must be set.");
+            }
+            if (mGranularity <= GRANULARITY_UNDEFINED) {
+                throw new IllegalArgumentException("Selection granularity must be set.");
+            }
+            return new SelectRangeGesture(mGranularity, mStartArea, mEndArea, mFallbackText);
+        }
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    @NonNull
+    public static final Parcelable.Creator<SelectRangeGesture> CREATOR =
+            new Parcelable.Creator<SelectRangeGesture>() {
+                @Override
+                public SelectRangeGesture createFromParcel(Parcel source) {
+                    return new SelectRangeGesture(source);
+                }
+
+                @Override
+                public SelectRangeGesture[] newArray(int size) {
+                    return new SelectRangeGesture[size];
+                }
+            };
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mGranularity, mStartArea, mEndArea, mFallbackText);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof SelectRangeGesture)) return false;
+
+        SelectRangeGesture that = (SelectRangeGesture) o;
+
+        if (mGranularity != that.mGranularity) return false;
+        if (!Objects.equals(mFallbackText, that.mFallbackText)) return false;
+        if (!Objects.equals(mStartArea, that.mStartArea)) return false;
+        return Objects.equals(mEndArea, that.mEndArea);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mFallbackText);
+        dest.writeInt(mGranularity);
+        dest.writeTypedObject(mStartArea, flags);
+        dest.writeTypedObject(mEndArea, flags);
+    }
+}
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 2c61280..aa2474d7 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,13 +17,17 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.TextUtils;
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
+import android.text.style.SpanUtils;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
 
 /*
  * This is supposed to be a *very* thin veneer over TextView.
@@ -69,8 +73,18 @@
  * See {@link android.R.styleable#EditText EditText Attributes},
  * {@link android.R.styleable#TextView TextView Attributes},
  * {@link android.R.styleable#View View Attributes}
+ *
+ * @attr ref android.R.styleable#EditText_enableTextStylingShortcuts
  */
 public class EditText extends TextView {
+
+    // True if the style shortcut is enabled.
+    private boolean mStyleShortcutsEnabled = false;
+
+    private static final int ID_BOLD = android.R.id.bold;
+    private static final int ID_ITALIC = android.R.id.italic;
+    private static final int ID_UNDERLINE = android.R.id.underline;
+
     public EditText(Context context) {
         this(context, null);
     }
@@ -85,6 +99,20 @@
 
     public EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+
+        final Resources.Theme theme = context.getTheme();
+        final TypedArray a = theme.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.EditText, defStyleAttr, defStyleRes);
+
+        final int n = a.getIndexCount();
+        for (int i = 0; i < n; ++i) {
+            int attr = a.getIndex(i);
+            switch (attr) {
+                case com.android.internal.R.styleable.EditText_enableTextStylingShortcuts:
+                    mStyleShortcutsEnabled = a.getBoolean(attr, false);
+                    break;
+            }
+        }
     }
 
     @Override
@@ -178,4 +206,77 @@
     protected boolean supportsAutoSizeText() {
         return false;
     }
+
+    @Override
+    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+        if (event.hasModifiers(KeyEvent.META_CTRL_ON)) {
+            // Handle Ctrl-only shortcuts.
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_B:
+                    if (mStyleShortcutsEnabled && hasSelection()) {
+                        return onTextContextMenuItem(ID_BOLD);
+                    }
+                    break;
+                case KeyEvent.KEYCODE_I:
+                    if (mStyleShortcutsEnabled && hasSelection()) {
+                        return onTextContextMenuItem(ID_ITALIC);
+                    }
+                    break;
+                case KeyEvent.KEYCODE_U:
+                    if (mStyleShortcutsEnabled && hasSelection()) {
+                        return onTextContextMenuItem(ID_UNDERLINE);
+                    }
+                    break;
+            }
+        }
+        return super.onKeyShortcut(keyCode, event);
+    }
+
+    @Override
+    public boolean onTextContextMenuItem(int id) {
+        // TODO: Move to switch-case once the resource ID is finalized.
+        if (id == ID_BOLD || id == ID_ITALIC || id == ID_UNDERLINE) {
+            return performStylingAction(id);
+        }
+        return super.onTextContextMenuItem(id);
+    }
+
+    private boolean performStylingAction(int actionId) {
+        final int selectionStart = getSelectionStart();
+        final int selectionEnd = getSelectionEnd();
+        if (selectionStart < 0 || selectionEnd < 0) {
+            return false;  // There is no selection.
+        }
+        int min = Math.min(selectionStart, selectionEnd);
+        int max = Math.max(selectionStart, selectionEnd);
+
+
+        Spannable spannable = getText();
+        if (actionId == ID_BOLD) {
+            return SpanUtils.toggleBold(spannable, min, max);
+        } else if (actionId == ID_ITALIC) {
+            return SpanUtils.toggleItalic(spannable, min, max);
+        } else if (actionId == ID_UNDERLINE) {
+            return SpanUtils.toggleUnderline(spannable, min, max);
+        }
+
+        return false;
+    }
+
+    /**
+     * Enables styls shortcuts, e.g. Ctrl+B for making text bold.
+     *
+     * @param enabled true for enabled, false for disabled.
+     */
+    public void setStyleShortcutsEnabled(boolean enabled) {
+        mStyleShortcutsEnabled = enabled;
+    }
+
+    /**
+     * Return true if style shortcut is enabled, otherwise returns false.
+     * @return true if style shortcut is enabled, otherwise returns false.
+     */
+    public boolean isStyleShortcutEnabled() {
+        return mStyleShortcutsEnabled;
+    }
 }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index cebaa76..a2a198a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4583,7 +4583,6 @@
      */
     private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
         final CursorAnchorInfo.Builder mSelectionInfoBuilder = new CursorAnchorInfo.Builder();
-        final int[] mTmpIntOffset = new int[2];
         final Matrix mViewToScreenMatrix = new Matrix();
 
         @Override
@@ -4635,9 +4634,8 @@
             builder.setSelectionRange(selectionStart, mTextView.getSelectionEnd());
 
             // Construct transformation matrix from view local coordinates to screen coordinates.
-            mViewToScreenMatrix.set(mTextView.getMatrix());
-            mTextView.getLocationOnScreen(mTmpIntOffset);
-            mViewToScreenMatrix.postTranslate(mTmpIntOffset[0], mTmpIntOffset[1]);
+            mViewToScreenMatrix.reset();
+            mTextView.transformMatrixToGlobal(mViewToScreenMatrix);
             builder.setMatrix(mViewToScreenMatrix);
 
             if (includeEditorBounds) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index be6b08f..075aa6c 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -148,6 +148,9 @@
             startSelectionActionMode(null);
         } else {
             resetTextClassificationHelper();
+            if (mSmartSelectSprite != null && mSmartSelectSprite.isAnimationActive()) {
+                mSmartSelectSprite.cancelAnimation();
+            }
             mTextClassificationAsyncTask = new TextClassificationAsyncTask(
                     mTextView,
                     mTextClassificationHelper.getTimeoutDuration(),
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 18ebe30..68b902f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7644,7 +7644,7 @@
         createEditorIfNeeded();
         mEditor.setError(error, icon);
         notifyViewAccessibilityStateChangedIfNeeded(
-                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_INVALID);
     }
 
     @Override
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
new file mode 100644
index 0000000..887d027
--- /dev/null
+++ b/core/java/android/window/ScreenCapture.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.SurfaceControl;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles display and layer captures for the system.
+ *
+ * @hide
+ */
+public class ScreenCapture {
+    private static final String TAG = "ScreenCapture";
+
+    private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
+            ScreenCaptureListener captureListener);
+    private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
+            ScreenCaptureListener captureListener);
+
+    /**
+     * @param captureArgs Arguments about how to take the screenshot
+     * @param captureListener A listener to receive the screenshot callback
+     * @hide
+     */
+    public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
+            @NonNull ScreenCaptureListener captureListener) {
+        return nativeCaptureDisplay(captureArgs, captureListener);
+    }
+
+    /**
+     * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with
+     * the content.
+     *
+     * @hide
+     */
+    public static ScreenshotHardwareBuffer captureDisplay(
+            DisplayCaptureArgs captureArgs) {
+        SyncScreenCaptureListener
+                screenCaptureListener = new SyncScreenCaptureListener();
+
+        int status = captureDisplay(captureArgs, screenCaptureListener);
+        if (status != 0) {
+            return null;
+        }
+
+        return screenCaptureListener.waitForScreenshot();
+    }
+
+    /**
+     * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
+     *
+     * @param layer            The root layer to capture.
+     * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
+     *                         Rect()' or null if no cropping is desired. If the root layer does not
+     *                         have a buffer or a crop set, then a non-empty source crop must be
+     *                         specified.
+     * @param frameScale       The desired scale of the returned buffer; the raw
+     *                         screen will be scaled up/down.
+     *
+     * @return Returns a HardwareBuffer that contains the layer capture.
+     * @hide
+     */
+    public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
+            float frameScale) {
+        return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
+    }
+
+    /**
+     * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
+     *
+     * @param layer            The root layer to capture.
+     * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
+     *                         Rect()' or null if no cropping is desired. If the root layer does not
+     *                         have a buffer or a crop set, then a non-empty source crop must be
+     *                         specified.
+     * @param frameScale       The desired scale of the returned buffer; the raw
+     *                         screen will be scaled up/down.
+     * @param format           The desired pixel format of the returned buffer.
+     *
+     * @return Returns a HardwareBuffer that contains the layer capture.
+     * @hide
+     */
+    public static ScreenshotHardwareBuffer captureLayers(@NonNull SurfaceControl layer,
+            @Nullable Rect sourceCrop, float frameScale, int format) {
+        LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+                .setSourceCrop(sourceCrop)
+                .setFrameScale(frameScale)
+                .setPixelFormat(format)
+                .build();
+
+        return captureLayers(captureArgs);
+    }
+
+    /**
+     * @hide
+     */
+    public static ScreenshotHardwareBuffer captureLayers(
+            LayerCaptureArgs captureArgs) {
+        SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
+
+        int status = captureLayers(captureArgs, screenCaptureListener);
+        if (status != 0) {
+            return null;
+        }
+
+        return screenCaptureListener.waitForScreenshot();
+    }
+
+    /**
+     * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
+     * handles to exclude.
+     * @hide
+     */
+    public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
+            Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
+        LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+                .setSourceCrop(sourceCrop)
+                .setFrameScale(frameScale)
+                .setPixelFormat(format)
+                .setExcludeLayers(exclude)
+                .build();
+
+        return captureLayers(captureArgs);
+    }
+
+    /**
+     * @param captureArgs Arguments about how to take the screenshot
+     * @param captureListener A listener to receive the screenshot callback
+     * @hide
+     */
+    public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
+            @NonNull ScreenCaptureListener captureListener) {
+        return nativeCaptureLayers(captureArgs, captureListener);
+    }
+
+    /**
+     * @hide
+     */
+    public interface ScreenCaptureListener {
+        /**
+         * The callback invoked when the screen capture is complete.
+         * @param hardwareBuffer Data containing info about the screen capture.
+         */
+        void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer);
+    }
+
+    /**
+     * A wrapper around HardwareBuffer that contains extra information about how to
+     * interpret the screenshot HardwareBuffer.
+     *
+     * @hide
+     */
+    public static class ScreenshotHardwareBuffer {
+        private final HardwareBuffer mHardwareBuffer;
+        private final ColorSpace mColorSpace;
+        private final boolean mContainsSecureLayers;
+        private final boolean mContainsHdrLayers;
+
+        public ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace,
+                boolean containsSecureLayers, boolean containsHdrLayers) {
+            mHardwareBuffer = hardwareBuffer;
+            mColorSpace = colorSpace;
+            mContainsSecureLayers = containsSecureLayers;
+            mContainsHdrLayers = containsHdrLayers;
+        }
+
+       /**
+        * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
+        * @param hardwareBuffer The existing HardwareBuffer object
+        * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+        * @param containsSecureLayers Indicates whether this graphic buffer contains captured
+        *                             contents of secure layers, in which case the screenshot
+        *                             should not be persisted.
+        * @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
+        */
+        private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
+                int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
+            ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
+            return new ScreenshotHardwareBuffer(
+                    hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
+        }
+
+        public ColorSpace getColorSpace() {
+            return mColorSpace;
+        }
+
+        public HardwareBuffer getHardwareBuffer() {
+            return mHardwareBuffer;
+        }
+
+        /**
+         * Whether this screenshot contains secure layers
+         */
+        public boolean containsSecureLayers() {
+            return mContainsSecureLayers;
+        }
+        /**
+         * Returns whether the screenshot contains at least one HDR layer.
+         * This information may be useful for informing the display whether this screenshot
+         * is allowed to be dimmed to SDR white.
+         */
+        public boolean containsHdrLayers() {
+            return mContainsHdrLayers;
+        }
+
+        /**
+         * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it.
+         * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap
+         * into
+         * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
+         *
+         * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to
+         * directly
+         * use the {@link HardwareBuffer} directly.
+         *
+         * @return Bitmap generated from the {@link HardwareBuffer}
+         */
+        public Bitmap asBitmap() {
+            if (mHardwareBuffer == null) {
+                Log.w(TAG, "Failed to take screenshot. Null screenshot object");
+                return null;
+            }
+            return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace);
+        }
+    }
+
+    private static class SyncScreenCaptureListener implements ScreenCaptureListener {
+        private static final int SCREENSHOT_WAIT_TIME_S = 1;
+        private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
+        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+        @Override
+        public void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
+            mScreenshotHardwareBuffer = hardwareBuffer;
+            mCountDownLatch.countDown();
+        }
+
+        private ScreenshotHardwareBuffer waitForScreenshot() {
+            try {
+                mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to wait for screen capture result", e);
+            }
+
+            return mScreenshotHardwareBuffer;
+        }
+    }
+
+    /**
+     * A common arguments class used for various screenshot requests. This contains arguments that
+     * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
+     * @hide
+     */
+    private abstract static class CaptureArgs {
+        private final int mPixelFormat;
+        private final Rect mSourceCrop = new Rect();
+        private final float mFrameScaleX;
+        private final float mFrameScaleY;
+        private final boolean mCaptureSecureLayers;
+        private final boolean mAllowProtected;
+        private final long mUid;
+        private final boolean mGrayscale;
+
+        private CaptureArgs(Builder<? extends Builder<?>> builder) {
+            mPixelFormat = builder.mPixelFormat;
+            mSourceCrop.set(builder.mSourceCrop);
+            mFrameScaleX = builder.mFrameScaleX;
+            mFrameScaleY = builder.mFrameScaleY;
+            mCaptureSecureLayers = builder.mCaptureSecureLayers;
+            mAllowProtected = builder.mAllowProtected;
+            mUid = builder.mUid;
+            mGrayscale = builder.mGrayscale;
+        }
+
+        /**
+         * The Builder class used to construct {@link CaptureArgs}
+         *
+         * @param <T> A builder that extends {@link Builder}
+         */
+        abstract static class Builder<T extends Builder<T>> {
+            private int mPixelFormat = PixelFormat.RGBA_8888;
+            private final Rect mSourceCrop = new Rect();
+            private float mFrameScaleX = 1;
+            private float mFrameScaleY = 1;
+            private boolean mCaptureSecureLayers;
+            private boolean mAllowProtected;
+            private long mUid = -1;
+            private boolean mGrayscale;
+
+            /**
+             * The desired pixel format of the returned buffer.
+             */
+            public T setPixelFormat(int pixelFormat) {
+                mPixelFormat = pixelFormat;
+                return getThis();
+            }
+
+            /**
+             * The portion of the screen to capture into the buffer. Caller may pass  in
+             * 'new Rect()' or null if no cropping is desired.
+             */
+            public T setSourceCrop(@Nullable Rect sourceCrop) {
+                if (sourceCrop == null) {
+                    mSourceCrop.setEmpty();
+                } else {
+                    mSourceCrop.set(sourceCrop);
+                }
+                return getThis();
+            }
+
+            /**
+             * The desired scale of the returned buffer. The raw screen will be scaled up/down.
+             */
+            public T setFrameScale(float frameScale) {
+                mFrameScaleX = frameScale;
+                mFrameScaleY = frameScale;
+                return getThis();
+            }
+
+            /**
+             * The desired scale of the returned buffer, allowing separate values for x and y scale.
+             * The raw screen will be scaled up/down.
+             */
+            public T setFrameScale(float frameScaleX, float frameScaleY) {
+                mFrameScaleX = frameScaleX;
+                mFrameScaleY = frameScaleY;
+                return getThis();
+            }
+
+            /**
+             * Whether to allow the screenshot of secure layers. Warning: This should only be done
+             * if the content will be placed in a secure SurfaceControl.
+             *
+             * @see ScreenshotHardwareBuffer#containsSecureLayers()
+             */
+            public T setCaptureSecureLayers(boolean captureSecureLayers) {
+                mCaptureSecureLayers = captureSecureLayers;
+                return getThis();
+            }
+
+            /**
+             * Whether to allow the screenshot of protected (DRM) content. Warning: The screenshot
+             * cannot be read in unprotected space.
+             *
+             * @see HardwareBuffer#USAGE_PROTECTED_CONTENT
+             */
+            public T setAllowProtected(boolean allowProtected) {
+                mAllowProtected = allowProtected;
+                return getThis();
+            }
+
+            /**
+             * Set the uid of the content that should be screenshot. The code will skip any surfaces
+             * that don't belong to the specified uid.
+             */
+            public T setUid(long uid) {
+                mUid = uid;
+                return getThis();
+            }
+
+            /**
+             * Set whether the screenshot should use grayscale or not.
+             */
+            public T setGrayscale(boolean grayscale) {
+                mGrayscale = grayscale;
+                return getThis();
+            }
+
+            /**
+             * Each sub class should return itself to allow the builder to chain properly
+             */
+            abstract T getThis();
+        }
+    }
+
+    /**
+     * The arguments class used to make display capture requests.
+     *
+     * @see #nativeCaptureDisplay(DisplayCaptureArgs, ScreenCaptureListener)
+     * @hide
+     */
+    public static class DisplayCaptureArgs extends CaptureArgs {
+        private final IBinder mDisplayToken;
+        private final int mWidth;
+        private final int mHeight;
+        private final boolean mUseIdentityTransform;
+
+        private DisplayCaptureArgs(Builder builder) {
+            super(builder);
+            mDisplayToken = builder.mDisplayToken;
+            mWidth = builder.mWidth;
+            mHeight = builder.mHeight;
+            mUseIdentityTransform = builder.mUseIdentityTransform;
+        }
+
+        /**
+         * The Builder class used to construct {@link DisplayCaptureArgs}
+         */
+        public static class Builder extends CaptureArgs.Builder<Builder> {
+            private IBinder mDisplayToken;
+            private int mWidth;
+            private int mHeight;
+            private boolean mUseIdentityTransform;
+
+            /**
+             * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+             * remains valid.
+             */
+            public DisplayCaptureArgs build() {
+                if (mDisplayToken == null) {
+                    throw new IllegalStateException(
+                            "Can't take screenshot with null display token");
+                }
+                return new DisplayCaptureArgs(this);
+            }
+
+            public Builder(IBinder displayToken) {
+                setDisplayToken(displayToken);
+            }
+
+            /**
+             * The display to take the screenshot of.
+             */
+            public Builder setDisplayToken(IBinder displayToken) {
+                mDisplayToken = displayToken;
+                return this;
+            }
+
+            /**
+             * Set the desired size of the returned buffer. The raw screen  will be  scaled down to
+             * this size
+             *
+             * @param width  The desired width of the returned buffer. Caller may pass in 0 if no
+             *               scaling is desired.
+             * @param height The desired height of the returned buffer. Caller may pass in 0 if no
+             *               scaling is desired.
+             */
+            public Builder setSize(int width, int height) {
+                mWidth = width;
+                mHeight = height;
+                return this;
+            }
+
+            /**
+             * Replace the rotation transform of the display with the identity transformation while
+             * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0
+             * orientation. Set this value to false if the screenshot should be taken in the
+             * current screen orientation.
+             */
+            public Builder setUseIdentityTransform(boolean useIdentityTransform) {
+                mUseIdentityTransform = useIdentityTransform;
+                return this;
+            }
+
+            @Override
+            Builder getThis() {
+                return this;
+            }
+        }
+    }
+
+    /**
+     * The arguments class used to make layer capture requests.
+     *
+     * @see #nativeCaptureLayers(LayerCaptureArgs, ScreenCaptureListener)
+     * @hide
+     */
+    public static class LayerCaptureArgs extends CaptureArgs {
+        private final long mNativeLayer;
+        private final long[] mNativeExcludeLayers;
+        private final boolean mChildrenOnly;
+
+        private LayerCaptureArgs(Builder builder) {
+            super(builder);
+            mChildrenOnly = builder.mChildrenOnly;
+            mNativeLayer = builder.mLayer.mNativeObject;
+            if (builder.mExcludeLayers != null) {
+                mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
+                for (int i = 0; i < builder.mExcludeLayers.length; i++) {
+                    mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+                }
+            } else {
+                mNativeExcludeLayers = null;
+            }
+        }
+
+        /**
+         * The Builder class used to construct {@link LayerCaptureArgs}
+         */
+        public static class Builder extends CaptureArgs.Builder<Builder> {
+            private SurfaceControl mLayer;
+            private SurfaceControl[] mExcludeLayers;
+            private boolean mChildrenOnly = true;
+
+            /**
+             * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+             * remains valid.
+             */
+            public LayerCaptureArgs build() {
+                if (mLayer == null) {
+                    throw new IllegalStateException(
+                            "Can't take screenshot with null layer");
+                }
+                return new LayerCaptureArgs(this);
+            }
+
+            public Builder(SurfaceControl layer) {
+                setLayer(layer);
+            }
+
+            /**
+             * The root layer to capture.
+             */
+            public Builder setLayer(SurfaceControl layer) {
+                mLayer = layer;
+                return this;
+            }
+
+
+            /**
+             * An array of layer handles to exclude.
+             */
+            public Builder setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
+                mExcludeLayers = excludeLayers;
+                return this;
+            }
+
+            /**
+             * Whether to include the layer itself in the screenshot or just the children and their
+             * descendants.
+             */
+            public Builder setChildrenOnly(boolean childrenOnly) {
+                mChildrenOnly = childrenOnly;
+                return this;
+            }
+
+            @Override
+            Builder getThis() {
+                return this;
+            }
+
+        }
+    }
+
+}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 3aee472..8df6541 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -20,12 +20,6 @@
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENTED_TO_TASK;
-import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
-import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
-import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
-import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
-import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
@@ -35,8 +29,6 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.app.WindowConfiguration;
-import android.content.Intent;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -55,21 +47,18 @@
 
     /**
      * Key to the {@link Throwable} in {@link TaskFragmentTransaction.Change#getErrorBundle()}.
-     * @hide
      */
     public static final String KEY_ERROR_CALLBACK_THROWABLE = "fragment_throwable";
 
     /**
      * Key to the {@link TaskFragmentInfo} in
      * {@link TaskFragmentTransaction.Change#getErrorBundle()}.
-     * @hide
      */
     public static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info";
 
     /**
      * Key to the {@link WindowContainerTransaction.HierarchyOp} in
      * {@link TaskFragmentTransaction.Change#getErrorBundle()}.
-     * @hide
      */
     public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";
 
@@ -195,7 +184,7 @@
      * Routes to {@link ITaskFragmentOrganizerController#applyTransaction} instead of
      * {@link IWindowOrganizerController#applyTransaction} for the different transition options.
      *
-     * @see #applyTransaction(WindowContainerTransaction, int, boolean, boolean)
+     * @see #applyTransaction(WindowContainerTransaction, int, boolean)
      */
     @Override
     public void applyTransaction(@NonNull WindowContainerTransaction wct) {
@@ -274,142 +263,13 @@
     }
 
     /**
-     * Called when a TaskFragment is created and organized by this organizer.
-     *
-     * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed. No
-     *              need to call {@link #applyTransaction} as it will be applied by the caller.
-     * @param taskFragmentInfo  Info of the TaskFragment that is created.
-     */
-    public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
-            @NonNull TaskFragmentInfo taskFragmentInfo) {}
-
-    /**
-     * Called when the status of an organized TaskFragment is changed.
-     *
-     * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed. No
-     *              need to call {@link #applyTransaction} as it will be applied by the caller.
-     * @param taskFragmentInfo  Info of the TaskFragment that is changed.
-     */
-    public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
-            @NonNull TaskFragmentInfo taskFragmentInfo) {}
-
-    /**
-     * Called when an organized TaskFragment is removed.
-     *
-     * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed. No
-     *              need to call {@link #applyTransaction} as it will be applied by the caller.
-     * @param taskFragmentInfo  Info of the TaskFragment that is removed.
-     */
-    public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
-            @NonNull TaskFragmentInfo taskFragmentInfo) {}
-
-    /**
-     * Called when the parent leaf Task of organized TaskFragments is changed.
-     * When the leaf Task is changed, the organizer may want to update the TaskFragments in one
-     * transaction.
-     *
-     * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
-     * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
-     * bounds.
-     *
-     * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed. No
-     *              need to call {@link #applyTransaction} as it will be applied by the caller.
-     * @param taskId    Id of the parent Task that is changed.
-     * @param parentConfig  Config of the parent Task.
-     */
-    public void onTaskFragmentParentInfoChanged(@NonNull WindowContainerTransaction wct, int taskId,
-            @NonNull Configuration parentConfig) {}
-
-    /**
-     * Called when the {@link WindowContainerTransaction} created with
-     * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
-     *
-     * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed. No
-     *              need to call {@link #applyTransaction} as it will be applied by the caller.
-     * @param errorCallbackToken    token set in
-     *                             {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)}
-     * @param taskFragmentInfo  The {@link TaskFragmentInfo}. This could be {@code null} if no
-     *                          TaskFragment created.
-     * @param opType            The {@link WindowContainerTransaction.HierarchyOp} of the failed
-     *                          transaction operation.
-     * @param exception             exception from the server side.
-     */
-    public void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
-            @NonNull IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo,
-            int opType, @NonNull Throwable exception) {}
-
-    /**
-     * Called when an Activity is reparented to the Task with organized TaskFragment. For example,
-     * when an Activity enters and then exits Picture-in-picture, it will be reparented back to its
-     * original Task. In this case, we need to notify the organizer so that it can check if the
-     * Activity matches any split rule.
-     *
-     * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed. No
-     *              need to call {@link #applyTransaction} as it will be applied by the caller.
-     * @param taskId            The Task that the activity is reparented to.
-     * @param activityIntent    The intent that the activity is original launched with.
-     * @param activityToken     If the activity belongs to the same process as the organizer, this
-     *                          will be the actual activity token; if the activity belongs to a
-     *                          different process, the server will generate a temporary token that
-     *                          the organizer can use to reparent the activity through
-     *                          {@link WindowContainerTransaction} if needed.
-     */
-    public void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
-            int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {}
-
-    /**
      * Called when the transaction is ready so that the organizer can update the TaskFragments based
      * on the changes in transaction.
-     * @hide
      */
     public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
-        // TODO(b/240519866): move to SplitController#onTransactionReady to make sure the whole
-        // transaction is handled in one sync block. Keep the implementation below to keep CTS
-        // compatibility. Remove in the next release.
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
-        final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
-        for (TaskFragmentTransaction.Change change : changes) {
-            final int taskId = change.getTaskId();
-            switch (change.getType()) {
-                case TYPE_TASK_FRAGMENT_APPEARED:
-                    onTaskFragmentAppeared(wct, change.getTaskFragmentInfo());
-                    break;
-                case TYPE_TASK_FRAGMENT_INFO_CHANGED:
-                    onTaskFragmentInfoChanged(wct, change.getTaskFragmentInfo());
-                    break;
-                case TYPE_TASK_FRAGMENT_VANISHED:
-                    onTaskFragmentVanished(wct, change.getTaskFragmentInfo());
-                    break;
-                case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
-                    onTaskFragmentParentInfoChanged(wct, taskId, change.getTaskConfiguration());
-                    break;
-                case TYPE_TASK_FRAGMENT_ERROR:
-                    final Bundle errorBundle = change.getErrorBundle();
-                    onTaskFragmentError(
-                            wct,
-                            change.getErrorCallbackToken(),
-                            errorBundle.getParcelable(
-                                    KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class),
-                            errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
-                            errorBundle.getSerializable(KEY_ERROR_CALLBACK_THROWABLE,
-                                    java.lang.Throwable.class));
-                    break;
-                case TYPE_ACTIVITY_REPARENTED_TO_TASK:
-                    onActivityReparentedToTask(
-                            wct,
-                            change.getTaskId(),
-                            change.getActivityIntent(),
-                            change.getActivityToken());
-                    break;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown TaskFragmentEvent=" + change.getType());
-            }
-        }
-
-        // Notify the server, and the server should apply the WindowContainerTransaction.
-        onTransactionHandled(transaction.getTransactionToken(), wct, getTransitionType(wct),
-                false /* shouldApplyIndependently */);
+        // Notify the server to finish the transaction.
+        onTransactionHandled(transaction.getTransactionToken(), new WindowContainerTransaction(),
+                TRANSIT_NONE, false /* shouldApplyIndependently */);
     }
 
     private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 84a5fea..04fcd3a 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -21,6 +21,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Binder;
@@ -40,6 +42,7 @@
  * @see TaskFragmentTransaction.Change
  * @hide
  */
+@TestApi
 public final class TaskFragmentTransaction implements Parcelable {
 
     /** Unique token to represent this transaction. */
@@ -63,6 +66,7 @@
         dest.writeTypedList(mChanges);
     }
 
+    @NonNull
     public IBinder getTransactionToken() {
         return mTransactionToken;
     }
@@ -105,6 +109,7 @@
         return 0;
     }
 
+    @NonNull
     public static final Creator<TaskFragmentTransaction> CREATOR = new Creator<>() {
         @Override
         public TaskFragmentTransaction createFromParcel(Parcel in) {
@@ -218,24 +223,28 @@
         }
 
         /** The change is related to the TaskFragment created with this unique token. */
+        @NonNull
         public Change setTaskFragmentToken(@NonNull IBinder taskFragmentToken) {
             mTaskFragmentToken = requireNonNull(taskFragmentToken);
             return this;
         }
 
         /** Info of the embedded TaskFragment. */
+        @NonNull
         public Change setTaskFragmentInfo(@NonNull TaskFragmentInfo info) {
             mTaskFragmentInfo = requireNonNull(info);
             return this;
         }
 
         /** Task id the parent Task. */
+        @NonNull
         public Change setTaskId(int taskId) {
             mTaskId = taskId;
             return this;
         }
 
         /** Configuration of the parent Task. */
+        @NonNull
         public Change setTaskConfiguration(@NonNull Configuration configuration) {
             mTaskConfiguration = requireNonNull(configuration);
             return this;
@@ -246,6 +255,7 @@
          * from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
          * report back.
          */
+        @NonNull
         public Change setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
             mErrorCallbackToken = errorCallbackToken;
             return this;
@@ -255,6 +265,7 @@
          * Bundle with necessary info about the failure operation of
          * {@link #TYPE_TASK_FRAGMENT_ERROR}.
          */
+        @NonNull
         public Change setErrorBundle(@NonNull Bundle errorBundle) {
             mErrorBundle = requireNonNull(errorBundle);
             return this;
@@ -264,6 +275,7 @@
          * Intent of the activity that is reparented to the Task for
          * {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}.
          */
+        @NonNull
         public Change setActivityIntent(@NonNull Intent intent) {
             mActivityIntent = requireNonNull(intent);
             return this;
@@ -276,6 +288,7 @@
          * a temporary token that the organizer can use to reparent the activity through
          * {@link WindowContainerTransaction} if needed.
          */
+        @NonNull
         public Change setActivityToken(@NonNull IBinder activityToken) {
             mActivityToken = requireNonNull(activityToken);
             return this;
@@ -310,11 +323,12 @@
             return mErrorCallbackToken;
         }
 
-        @Nullable
+        @NonNull
         public Bundle getErrorBundle() {
-            return mErrorBundle;
+            return mErrorBundle != null ? mErrorBundle : Bundle.EMPTY;
         }
 
+        @SuppressLint("IntentBuilderName") // This is not creating new Intent.
         @Nullable
         public Intent getActivityIntent() {
             return mActivityIntent;
@@ -335,6 +349,7 @@
             return 0;
         }
 
+        @NonNull
         public static final Creator<Change> CREATOR = new Creator<>() {
             @Override
             public Change createFromParcel(Parcel in) {
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 8ca763e..33ea2e4 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -110,11 +110,11 @@
     /** The container is an input-method window. */
     public static final int FLAG_IS_INPUT_METHOD = 1 << 8;
 
-    /** The container is ActivityEmbedding embedded. */
-    public static final int FLAG_IS_EMBEDDED = 1 << 9;
+    /** The container is in a Task with embedded activity. */
+    public static final int FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY = 1 << 9;
 
-    /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
-    public static final int FLAG_FIRST_CUSTOM = 1 << 10;
+    /** The container fills its parent Task before and after the transition. */
+    public static final int FLAG_FILLS_TASK = 1 << 10;
 
     /** The container is going to show IME on its task after the transition. */
     public static final int FLAG_WILL_IME_SHOWN = 1 << 11;
@@ -125,6 +125,9 @@
     /** The container attaches work profile thumbnail for cross profile animation. */
     public static final int FLAG_CROSS_PROFILE_WORK_THUMBNAIL = 1 << 13;
 
+    /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
+    public static final int FLAG_FIRST_CUSTOM = 1 << 14;
+
     /** @hide */
     @IntDef(prefix = { "FLAG_" }, value = {
             FLAG_NONE,
@@ -137,9 +140,12 @@
             FLAG_OCCLUDES_KEYGUARD,
             FLAG_DISPLAY_HAS_ALERT_WINDOWS,
             FLAG_IS_INPUT_METHOD,
-            FLAG_IS_EMBEDDED,
-            FLAG_FIRST_CUSTOM,
-            FLAG_WILL_IME_SHOWN
+            FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY,
+            FLAG_FILLS_TASK,
+            FLAG_WILL_IME_SHOWN,
+            FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
+            FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
+            FLAG_FIRST_CUSTOM
     })
     public @interface ChangeFlags {}
 
@@ -322,28 +328,31 @@
             sb.append("IS_INPUT_METHOD");
         }
         if ((flags & FLAG_TRANSLUCENT) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT");
+            sb.append(sb.length() == 0 ? "" : "|").append("TRANSLUCENT");
         }
         if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "STARTING_WINDOW_TRANSFER");
+            sb.append(sb.length() == 0 ? "" : "|").append("STARTING_WINDOW_TRANSFER");
         }
         if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "IS_VOICE_INTERACTION");
+            sb.append(sb.length() == 0 ? "" : "|").append("IS_VOICE_INTERACTION");
         }
         if ((flags & FLAG_IS_DISPLAY) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY");
+            sb.append(sb.length() == 0 ? "" : "|").append("IS_DISPLAY");
         }
         if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD");
+            sb.append(sb.length() == 0 ? "" : "|").append("OCCLUDES_KEYGUARD");
         }
         if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS");
+            sb.append(sb.length() == 0 ? "" : "|").append("DISPLAY_HAS_ALERT_WINDOWS");
         }
-        if ((flags & FLAG_IS_EMBEDDED) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "IS_EMBEDDED");
+        if ((flags & FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY) != 0) {
+            sb.append(sb.length() == 0 ? "" : "|").append("IN_TASK_WITH_EMBEDDED_ACTIVITY");
+        }
+        if ((flags & FLAG_FILLS_TASK) != 0) {
+            sb.append(sb.length() == 0 ? "" : "|").append("FILLS_TASK");
         }
         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
-            sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM");
+            sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
         }
         return sb.toString();
     }
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 0976f45..a208634 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -28,6 +28,7 @@
 import android.app.IWindowToken;
 import android.app.ResourcesManager;
 import android.content.Context;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.inputmethodservice.AbstractInputMethodService;
 import android.os.Build;
@@ -221,6 +222,7 @@
         if (context == null) {
             return;
         }
+        CompatibilityInfo.applyOverrideScaleIfNeeded(newConfig);
         final boolean displayChanged;
         final boolean shouldUpdateResources;
         final int diff;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 1bc934d..5cf7e36 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -142,6 +142,7 @@
 import java.net.URISyntaxException;
 import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -2952,12 +2953,14 @@
 
     private void startFinishAnimation() {
         View rootView = findRootView();
-        rootView.startAnimation(new FinishAnimation(this, rootView));
+        if (rootView != null) {
+            rootView.startAnimation(new FinishAnimation(this, rootView));
+        }
     }
 
     private boolean maybeCancelFinishAnimation() {
         View rootView = findRootView();
-        Animation animation = rootView.getAnimation();
+        Animation animation = rootView == null ? null : rootView.getAnimation();
         if (animation instanceof FinishAnimation) {
             boolean hasEnded = animation.hasEnded();
             animation.cancel();
@@ -3721,6 +3724,7 @@
             this.mRows = rows;
             this.mCellCountPerRow = cellCountPerRow;
             this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
+            Arrays.fill(mCellVisibility, true);
             this.mListAdapterSupplier = listAdapterSupplier;
         }
 
@@ -4084,11 +4088,13 @@
      */
     private static class FinishAnimation extends AlphaAnimation implements
             Animation.AnimationListener {
+        @Nullable
         private Activity mActivity;
+        @Nullable
         private View mRootView;
         private final float mFromAlpha;
 
-        FinishAnimation(Activity activity, View rootView) {
+        FinishAnimation(@NonNull Activity activity, @NonNull View rootView) {
             super(rootView.getAlpha(), 0.0f);
             mActivity = activity;
             mRootView = rootView;
@@ -4112,7 +4118,9 @@
 
         @Override
         public void cancel() {
-            mRootView.setAlpha(mFromAlpha);
+            if (mRootView != null) {
+                mRootView.setAlpha(mFromAlpha);
+            }
             cleanup();
             super.cancel();
         }
@@ -4123,9 +4131,10 @@
 
         @Override
         public void onAnimationEnd(Animation animation) {
-            if (mActivity != null) {
-                mActivity.finish();
-                cleanup();
+            Activity activity = mActivity;
+            cleanup();
+            if (activity != null) {
+                activity.finish();
             }
         }
 
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index e57b90a..1ec5325 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -43,7 +43,6 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.app.chooser.ChooserTargetInfo;
 import com.android.internal.app.chooser.DisplayResolveInfo;
@@ -87,7 +86,7 @@
     private final ChooserActivityLogger mChooserActivityLogger;
 
     private int mNumShortcutResults = 0;
-    private final Map<TargetInfo, AsyncTask> mIconLoaders = new HashMap<>();
+    private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
     private boolean mApplySharingAppLimits;
 
     // Reserve spots for incoming direct share targets by adding placeholders
@@ -105,8 +104,6 @@
     private AppPredictor mAppPredictor;
     private AppPredictor.Callback mAppPredictorCallback;
 
-    private LoadDirectShareIconTaskProvider mTestLoadDirectShareTaskProvider;
-
     // For pinned direct share labels, if the text spans multiple lines, the TextView will consume
     // the full width, even if the characters actually take up less than that. Measure the actual
     // line widths and constrain the View's width based upon that so that the pin doesn't end up
@@ -243,6 +240,7 @@
         mListViewDataChanged = false;
     }
 
+
     private void createPlaceHolders() {
         mNumShortcutResults = 0;
         mServiceTargets.clear();
@@ -267,25 +265,31 @@
             return;
         }
 
-        if (info instanceof DisplayResolveInfo) {
-            DisplayResolveInfo dri = (DisplayResolveInfo) info;
-            holder.bindLabel(dri.getDisplayLabel(), dri.getExtendedInfo(), alwaysShowSubLabel());
-            startDisplayResolveInfoIconLoading(holder, dri);
-        } else {
+        if (!(info instanceof DisplayResolveInfo)) {
             holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel());
+            holder.bindIcon(info);
 
             if (info instanceof SelectableTargetInfo) {
-                SelectableTargetInfo selectableInfo = (SelectableTargetInfo) info;
                 // direct share targets should append the application name for a better readout
-                DisplayResolveInfo rInfo = selectableInfo.getDisplayResolveInfo();
+                DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo();
                 CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : "";
-                CharSequence extendedInfo = selectableInfo.getExtendedInfo();
-                String contentDescription = String.join(" ", selectableInfo.getDisplayLabel(),
+                CharSequence extendedInfo = info.getExtendedInfo();
+                String contentDescription = String.join(" ", info.getDisplayLabel(),
                         extendedInfo != null ? extendedInfo : "", appName);
                 holder.updateContentDescription(contentDescription);
-                startSelectableTargetInfoIconLoading(holder, selectableInfo);
+            }
+        } else {
+            DisplayResolveInfo dri = (DisplayResolveInfo) info;
+            holder.bindLabel(dri.getDisplayLabel(), dri.getExtendedInfo(), alwaysShowSubLabel());
+            LoadIconTask task = mIconLoaders.get(dri);
+            if (task == null) {
+                task = new LoadIconTask(dri, holder);
+                mIconLoaders.put(dri, task);
+                task.execute();
             } else {
-                holder.bindIcon(info);
+                // The holder was potentially changed as the underlying items were
+                // reshuffled, so reset the target holder
+                task.setViewHolder(holder);
             }
         }
 
@@ -326,32 +330,6 @@
         }
     }
 
-    private void startDisplayResolveInfoIconLoading(ViewHolder holder, DisplayResolveInfo info) {
-        LoadIconTask task = (LoadIconTask) mIconLoaders.get(info);
-        if (task == null) {
-            task = new LoadIconTask(info, holder);
-            mIconLoaders.put(info, task);
-            task.execute();
-        } else {
-            // The holder was potentially changed as the underlying items were
-            // reshuffled, so reset the target holder
-            task.setViewHolder(holder);
-        }
-    }
-
-    private void startSelectableTargetInfoIconLoading(
-            ViewHolder holder, SelectableTargetInfo info) {
-        LoadDirectShareIconTask task = (LoadDirectShareIconTask) mIconLoaders.get(info);
-        if (task == null) {
-            task = mTestLoadDirectShareTaskProvider == null
-                    ? new LoadDirectShareIconTask(info)
-                    : mTestLoadDirectShareTaskProvider.get();
-            mIconLoaders.put(info, task);
-            task.loadIcon();
-        }
-        task.setViewHolder(holder);
-    }
-
     void updateAlphabeticalList() {
         new AsyncTask<Void, Void, List<DisplayResolveInfo>>() {
             @Override
@@ -366,7 +344,7 @@
                 Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
                 for (DisplayResolveInfo info : allTargets) {
                     String resolvedTarget = info.getResolvedComponentName().getPackageName()
-                            + '#' + info.getDisplayLabel();
+                        + '#' + info.getDisplayLabel();
                     DisplayResolveInfo multiDri = consolidated.get(resolvedTarget);
                     if (multiDri == null) {
                         consolidated.put(resolvedTarget, info);
@@ -375,7 +353,7 @@
                     } else {
                         // create consolidated target from the single DisplayResolveInfo
                         MultiDisplayResolveInfo multiDisplayResolveInfo =
-                                new MultiDisplayResolveInfo(resolvedTarget, multiDri);
+                            new MultiDisplayResolveInfo(resolvedTarget, multiDri);
                         multiDisplayResolveInfo.addTarget(info);
                         consolidated.put(resolvedTarget, multiDisplayResolveInfo);
                     }
@@ -762,24 +740,10 @@
     }
 
     /**
-     * An alias for onBindView to use with unit tests.
-     */
-    @VisibleForTesting
-    public void testViewBind(View view, TargetInfo info, int position) {
-        onBindView(view, info, position);
-    }
-
-    @VisibleForTesting
-    public void setTestLoadDirectShareTaskProvider(LoadDirectShareIconTaskProvider provider) {
-        mTestLoadDirectShareTaskProvider = provider;
-    }
-
-    /**
      * Necessary methods to communicate between {@link ChooserListAdapter}
      * and {@link ChooserActivity}.
      */
-    @VisibleForTesting
-    public interface ChooserListCommunicator extends ResolverListCommunicator {
+    interface ChooserListCommunicator extends ResolverListCommunicator {
 
         int getMaxRankedTargets();
 
@@ -787,59 +751,4 @@
 
         boolean isSendAction(Intent targetIntent);
     }
-
-    /**
-     * Loads direct share targets icons.
-     */
-    @VisibleForTesting
-    public class LoadDirectShareIconTask extends AsyncTask<Void, Void, Void> {
-        private final SelectableTargetInfo mTargetInfo;
-        private ViewHolder mViewHolder;
-
-        private LoadDirectShareIconTask(SelectableTargetInfo targetInfo) {
-            mTargetInfo = targetInfo;
-        }
-
-        @Override
-        protected Void doInBackground(Void... voids) {
-            mTargetInfo.loadIcon();
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Void arg) {
-            if (mViewHolder != null) {
-                mViewHolder.bindIcon(mTargetInfo);
-                notifyDataSetChanged();
-            }
-        }
-
-        /**
-         * Specifies a view holder that will be updated when the task is completed.
-         */
-        public void setViewHolder(ViewHolder viewHolder) {
-            mViewHolder = viewHolder;
-            mViewHolder.bindIcon(mTargetInfo);
-            notifyDataSetChanged();
-        }
-
-        /**
-         * An alias for execute to use with unit tests.
-         */
-        public void loadIcon() {
-            execute();
-        }
-    }
-
-    /**
-     * An interface for the unit tests to override icon loading task creation
-     */
-    @VisibleForTesting
-    public interface LoadDirectShareIconTaskProvider {
-        /**
-         * Provides an instance of the task.
-         * @return
-         */
-        LoadDirectShareIconTask get();
-    }
 }
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 3a3baa7..66fff5c 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -834,11 +834,7 @@
         void onHandlePackagesChanged(ResolverListAdapter listAdapter);
     }
 
-    /**
-     * A view holder.
-     */
-    @VisibleForTesting
-    public static class ViewHolder {
+    static class ViewHolder {
         public View itemView;
         public Drawable defaultItemViewBackground;
 
@@ -846,8 +842,7 @@
         public TextView text2;
         public ImageView icon;
 
-        @VisibleForTesting
-        public ViewHolder(View view) {
+        ViewHolder(View view) {
             itemView = view;
             defaultItemViewBackground = view.getBackground();
             text = (TextView) view.findViewById(com.android.internal.R.id.text1);
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 37eab40..264e4f7 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -37,7 +37,6 @@
 import android.text.SpannableStringBuilder;
 import android.util.Log;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ChooserActivity;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
@@ -60,11 +59,8 @@
     private final String mDisplayLabel;
     private final PackageManager mPm;
     private final SelectableTargetInfoCommunicator mSelectableTargetInfoCommunicator;
-    @GuardedBy("this")
-    private ShortcutInfo mShortcutInfo;
     private Drawable mBadgeIcon = null;
     private CharSequence mBadgeContentDescription;
-    @GuardedBy("this")
     private Drawable mDisplayIcon;
     private final Intent mFillInIntent;
     private final int mFillInFlags;
@@ -82,7 +78,6 @@
         mModifiedScore = modifiedScore;
         mPm = mContext.getPackageManager();
         mSelectableTargetInfoCommunicator = selectableTargetInfoComunicator;
-        mShortcutInfo = shortcutInfo;
         mIsPinned = shortcutInfo != null && shortcutInfo.isPinned();
         if (sourceInfo != null) {
             final ResolveInfo ri = sourceInfo.getResolveInfo();
@@ -97,6 +92,8 @@
                 }
             }
         }
+        // TODO(b/121287224): do this in the background thread, and only for selected targets
+        mDisplayIcon = getChooserTargetIconDrawable(chooserTarget, shortcutInfo);
 
         if (sourceInfo != null) {
             mBackupResolveInfo = null;
@@ -121,10 +118,7 @@
         mChooserTarget = other.mChooserTarget;
         mBadgeIcon = other.mBadgeIcon;
         mBadgeContentDescription = other.mBadgeContentDescription;
-        synchronized (other) {
-            mShortcutInfo = other.mShortcutInfo;
-            mDisplayIcon = other.mDisplayIcon;
-        }
+        mDisplayIcon = other.mDisplayIcon;
         mFillInIntent = fillInIntent;
         mFillInFlags = flags;
         mModifiedScore = other.mModifiedScore;
@@ -147,25 +141,6 @@
         return mSourceInfo;
     }
 
-    /**
-     * Load display icon, if needed.
-     */
-    public void loadIcon() {
-        ShortcutInfo shortcutInfo;
-        Drawable icon;
-        synchronized (this) {
-            shortcutInfo = mShortcutInfo;
-            icon = mDisplayIcon;
-        }
-        if (icon == null && shortcutInfo != null) {
-            icon = getChooserTargetIconDrawable(mChooserTarget, shortcutInfo);
-            synchronized (this) {
-                mDisplayIcon = icon;
-                mShortcutInfo = null;
-            }
-        }
-    }
-
     private Drawable getChooserTargetIconDrawable(ChooserTarget target,
             @Nullable ShortcutInfo shortcutInfo) {
         Drawable directShareIcon = null;
@@ -295,7 +270,7 @@
     }
 
     @Override
-    public synchronized Drawable getDisplayIcon(Context context) {
+    public Drawable getDisplayIcon(Context context) {
         return mDisplayIcon;
     }
 
diff --git a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
index 7a219c6..17f9b7d 100644
--- a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
+++ b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
@@ -22,10 +22,14 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.DeleteGesture;
+import android.view.inputmethod.DeleteRangeGesture;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
+import android.view.inputmethod.SelectRangeGesture;
 import android.view.inputmethod.TextAttribute;
 
 import com.android.internal.infra.AndroidFuture;
@@ -93,12 +97,24 @@
     void performHandwritingSelectGesture(in InputConnectionCommandHeader header,
             in SelectGesture gesture, in ResultReceiver resultReceiver);
 
+    void performHandwritingSelectRangeGesture(in InputConnectionCommandHeader header,
+            in SelectRangeGesture gesture, in ResultReceiver resultReceiver);
+
     void performHandwritingInsertGesture(in InputConnectionCommandHeader header,
             in InsertGesture gesture, in ResultReceiver resultReceiver);
 
     void performHandwritingDeleteGesture(in InputConnectionCommandHeader header,
             in DeleteGesture gesture, in ResultReceiver resultReceiver);
 
+    void performHandwritingDeleteRangeGesture(in InputConnectionCommandHeader header,
+                in DeleteRangeGesture gesture, in ResultReceiver resultReceiver);
+
+    void performHandwritingRemoveSpaceGesture(in InputConnectionCommandHeader header,
+            in RemoveSpaceGesture gesture, in ResultReceiver resultReceiver);
+
+    void performHandwritingJoinOrSplitGesture(in InputConnectionCommandHeader header,
+            in JoinOrSplitGesture gesture, in ResultReceiver resultReceiver);
+
     void setComposingRegion(in InputConnectionCommandHeader header, int start, int end);
 
     void setComposingRegionWithTextAttribute(in InputConnectionCommandHeader header, int start,
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index b5fc05b..7f3144b 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.inputmethod;
 
-import android.annotation.AnyThread;
-import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.inputmethod.HandwritingGesture;
@@ -253,6 +253,8 @@
                 return "HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED";
             case SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION:
                 return "HIDE_SOFT_INPUT_IMM_DEPRECATION";
+            case SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR:
+                return "HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR";
             default:
                 return "Unknown=" + reason;
         }
@@ -270,31 +272,43 @@
         if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_SELECT) != 0) {
             joiner.add("SELECT");
         }
+        if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_SELECT_RANGE) != 0) {
+            joiner.add("SELECT_RANGE");
+        }
         if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_INSERT) != 0) {
             joiner.add("INSERT");
         }
         if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE) != 0) {
             joiner.add("DELETE");
         }
-
+        if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE_RANGE) != 0) {
+            joiner.add("DELETE_RANGE");
+        }
+        if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) != 0) {
+            joiner.add("REMOVE_SPACE");
+        }
+        if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT) != 0) {
+            joiner.add("JOIN_OR_SPLIT");
+        }
         return joiner.setEmptyValue("(none)").toString();
     }
 
     /**
-     * Return a fixed size string of the object.
-     * TODO(b/151575861): Take & return with StringBuilder to make more memory efficient.
+     * Dumps the given {@link View} related to input method focus state for debugging.
      */
-    @NonNull
-    @AnyThread
-    public static String objToString(Object obj) {
-        if (obj == null) {
+    public static String dumpViewInfo(@Nullable View view) {
+        if (view == null) {
             return "null";
         }
-        StringBuilder sb = new StringBuilder(64);
-        sb.setLength(0);
-        sb.append(obj.getClass().getName());
-        sb.append("@");
-        sb.append(Integer.toHexString(obj.hashCode()));
+        final StringBuilder sb = new StringBuilder();
+        sb.append(view);
+        sb.append(",focus=" + view.hasFocus());
+        sb.append(",windowFocus=" + view.hasWindowFocus());
+        sb.append(",window=" + view.getWindowToken());
+        sb.append(",displayId=" + view.getContext().getDisplayId());
+        sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
+        sb.append(",hasImeFocus=" + view.hasImeFocus());
+
         return sb.toString();
     }
 }
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index dd173a6..713e913 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -41,6 +41,7 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.DeleteGesture;
+import android.view.inputmethod.DeleteRangeGesture;
 import android.view.inputmethod.DumpableInputConnection;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.HandwritingGesture;
@@ -48,7 +49,10 @@
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
+import android.view.inputmethod.SelectRangeGesture;
 import android.view.inputmethod.TextAttribute;
 import android.view.inputmethod.TextSnapshot;
 
@@ -983,6 +987,14 @@
 
     @Dispatching(cancellable = true)
     @Override
+    public void performHandwritingSelectRangeGesture(
+            InputConnectionCommandHeader header, SelectRangeGesture gesture,
+            ResultReceiver resultReceiver) {
+        performHandwritingGestureInternal(header, gesture, resultReceiver);
+    }
+
+    @Dispatching(cancellable = true)
+    @Override
     public void performHandwritingInsertGesture(
             InputConnectionCommandHeader header, InsertGesture gesture,
             ResultReceiver resultReceiver) {
@@ -997,6 +1009,30 @@
         performHandwritingGestureInternal(header, gesture, resultReceiver);
     }
 
+    @Dispatching(cancellable = true)
+    @Override
+    public void performHandwritingDeleteRangeGesture(
+            InputConnectionCommandHeader header, DeleteRangeGesture gesture,
+            ResultReceiver resultReceiver) {
+        performHandwritingGestureInternal(header, gesture, resultReceiver);
+    }
+
+    @Dispatching(cancellable = true)
+    @Override
+    public void performHandwritingRemoveSpaceGesture(
+            InputConnectionCommandHeader header, RemoveSpaceGesture gesture,
+            ResultReceiver resultReceiver) {
+        performHandwritingGestureInternal(header, gesture, resultReceiver);
+    }
+
+    @Dispatching(cancellable = true)
+    @Override
+    public void performHandwritingJoinOrSplitGesture(
+            InputConnectionCommandHeader header, JoinOrSplitGesture gesture,
+            ResultReceiver resultReceiver) {
+        performHandwritingGestureInternal(header, gesture, resultReceiver);
+    }
+
     private <T extends HandwritingGesture> void performHandwritingGestureInternal(
             InputConnectionCommandHeader header,  T gesture, ResultReceiver resultReceiver) {
         dispatchWithTracing("performHandwritingGesture", () -> {
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index f5b58c0..f1635eb 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -63,7 +63,8 @@
         SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED,
-        SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION})
+        SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION,
+        SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR})
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
     int SHOW_SOFT_INPUT = 0;
@@ -247,4 +248,9 @@
      * {@link InputMethodManager#hideSoftInputFromInputMethod(IBinder, int)}.
      */
     int HIDE_SOFT_INPUT_IMM_DEPRECATION = 31;
+
+    /**
+     * Hide soft input when the window gained focus without an editor from the IME shown window.
+     */
+    int HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR = 32;
 }
diff --git a/core/java/com/android/internal/jank/DisplayResolutionTracker.java b/core/java/com/android/internal/jank/DisplayResolutionTracker.java
new file mode 100644
index 0000000..72a1bac
--- /dev/null
+++ b/core/java/com/android/internal/jank/DisplayResolutionTracker.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.jank;
+
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.Handler;
+import android.util.SparseArray;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+* A class that tracks the display resolutions.
+* @hide
+*/
+public class DisplayResolutionTracker {
+    private static final String TAG = DisplayResolutionTracker.class.getSimpleName();
+
+    public static final int RESOLUTION_UNKNOWN =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__UNKNOWN_RESOLUTION;
+    public static final int RESOLUTION_SD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__SD;
+    public static final int RESOLUTION_HD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__HD;
+    public static final int RESOLUTION_FHD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__FHD;
+    public static final int RESOLUTION_QHD =
+            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_RESOLUTION__QHD;
+
+    /** @hide */
+    @IntDef({
+        RESOLUTION_UNKNOWN,
+        RESOLUTION_SD,
+        RESOLUTION_HD,
+        RESOLUTION_FHD,
+        RESOLUTION_QHD,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Resolution {
+    }
+
+    private final DisplayInterface mManager;
+    private final SparseArray<Integer> mResolutions = new SparseArray<>();
+    private final Object mLock = new Object();
+
+    public DisplayResolutionTracker(@Nullable Handler handler) {
+        this(DisplayInterface.getDefault(handler));
+    }
+
+    @VisibleForTesting
+    public DisplayResolutionTracker(DisplayInterface manager) {
+        mManager = manager;
+        mManager.registerDisplayListener(new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+                updateDisplay(displayId);
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                updateDisplay(displayId);
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                // Not in the event mask below, won't be called.
+            }
+        });
+    }
+
+    private void updateDisplay(int displayId) {
+        DisplayInfo info = mManager.getDisplayInfo(displayId);
+        if (info == null) {
+            return;
+        }
+        @Resolution int resolution = getResolution(info);
+
+        synchronized (mLock) {
+            mResolutions.put(displayId, resolution);
+        }
+    }
+
+    /**
+     * Returns the (cached) resolution of the display with the given ID.
+     */
+    @Resolution
+    public int getResolution(int displayId) {
+        return mResolutions.get(displayId, RESOLUTION_UNKNOWN);
+    }
+
+    /**
+     * Returns the resolution of the given {@link DisplayInfo}.
+     */
+    @VisibleForTesting
+    @Resolution
+    public static int getResolution(DisplayInfo info) {
+        int smaller = Math.min(info.logicalWidth, info.logicalHeight);
+        int larger = Math.max(info.logicalWidth, info.logicalHeight);
+        if (smaller < 720 || larger < 1280) {
+            return RESOLUTION_SD;
+        } else if (smaller < 1080 || larger < 1920) {
+            return RESOLUTION_HD;
+        } else if (smaller < 1440 || larger < 2560) {
+            return RESOLUTION_FHD;
+        } else {
+            return RESOLUTION_QHD;
+        }
+    }
+
+    /**
+     * Wrapper around the final {@link DisplayManagerGlobal} class.
+     * @hide
+     */
+    @VisibleForTesting
+    public interface DisplayInterface {
+        /** Reurns an implementation wrapping {@link DisplayManagerGlobal}. */
+        static DisplayInterface getDefault(@Nullable Handler handler) {
+            DisplayManagerGlobal manager = DisplayManagerGlobal.getInstance();
+            return new DisplayInterface() {
+                @Override
+                public void registerDisplayListener(DisplayManager.DisplayListener listener) {
+                    manager.registerDisplayListener(listener, handler,
+                            DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                                    | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
+                }
+
+                @Override
+                public DisplayInfo getDisplayInfo(int displayId) {
+                    return manager.getDisplayInfo(displayId);
+                }
+            };
+        }
+
+        /** {@see DisplayManagerGlobal#registerDisplayListener} */
+        void registerDisplayListener(DisplayManager.DisplayListener listener);
+        /** {@see DisplayManagerGlobal#getDisplayInfo} */
+        DisplayInfo getDisplayInfo(int displayId);
+    }
+}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 48343803..e4195d2 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -100,6 +100,7 @@
     private final Session mSession;
     private final ViewRootWrapper mViewRoot;
     private final SurfaceControlWrapper mSurfaceControlWrapper;
+    private final int mDisplayId;
     private final ViewRootImpl.SurfaceChangedCallback mSurfaceChangedCallback;
     private final Handler mHandler;
     private final ChoreographerWrapper mChoreographer;
@@ -213,6 +214,7 @@
         mTraceThresholdMissedFrames = traceThresholdMissedFrames;
         mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
         mListener = listener;
+        mDisplayId = config.getDisplayId();
 
         if (mSurfaceOnly) {
             mSurfaceControl = config.getSurfaceControl();
@@ -625,6 +627,7 @@
         if (mSession.logToStatsd()) {
             mStatsLog.write(
                     FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
+                    mDisplayId,
                     mSession.getStatsdInteractionType(),
                     totalFramesCount,
                     missedFramesCount,
@@ -785,9 +788,17 @@
     }
 
     public static class StatsLogWrapper {
-        public void write(int code,
+        private final DisplayResolutionTracker mDisplayResolutionTracker;
+
+        public StatsLogWrapper(DisplayResolutionTracker displayResolutionTracker) {
+            mDisplayResolutionTracker = displayResolutionTracker;
+        }
+
+        /** {@see FrameworkStatsLog#write) */
+        public void write(int code, int displayId,
                 int arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7) {
-            FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+            FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+                    mDisplayResolutionTracker.getResolution(displayId));
         }
     }
 
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index fc4e041..b5991b3 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -306,6 +306,7 @@
     @GuardedBy("mLock")
     private final SparseArray<Runnable> mTimeoutActions;
     private final HandlerThread mWorker;
+    private final DisplayResolutionTracker mDisplayResolutionTracker;
     private final Object mLock = new Object();
 
     private volatile boolean mEnabled = DEFAULT_ENABLED;
@@ -408,6 +409,7 @@
         mWorker = worker;
         mWorker.start();
         mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
+        mDisplayResolutionTracker = new DisplayResolutionTracker(worker.getThreadHandler());
 
         // Post initialization to the background in case we're running on the main
         // thread.
@@ -443,7 +445,8 @@
         final FrameMetricsWrapper frameMetrics = new FrameMetricsWrapper();
 
         return new FrameTracker(this, session, config.getHandler(), threadedRenderer, viewRoot,
-                surfaceControl, choreographer, frameMetrics, new FrameTracker.StatsLogWrapper(),
+                surfaceControl, choreographer, frameMetrics,
+                new FrameTracker.StatsLogWrapper(mDisplayResolutionTracker),
                 mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis,
                 eventsListener, config);
     }
@@ -1098,6 +1101,14 @@
         public Handler getHandler() {
             return mHandler;
         }
+
+        /**
+         * @return the ID of the display this interaction in on.
+         */
+        @VisibleForTesting
+        public int getDisplayId() {
+            return (mSurfaceOnly ? mContext.getDisplay() : mView.getDisplay()).getDisplayId();
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index 50dcca64..664aeee 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -98,6 +98,18 @@
             native_getValues(mNativeObject, array);
         }
 
+        /**
+         * Combines contained values into a smaller array by aggregating them
+         * according to an index map.
+         */
+        public boolean combineValues(long[] array, int[] indexMap) {
+            if (indexMap.length != mLength) {
+                throw new IllegalArgumentException(
+                        "Wrong index map size " + indexMap.length + ", expected " + mLength);
+            }
+            return native_combineValues(mNativeObject, array, indexMap);
+        }
+
         @Override
         public String toString() {
             final long[] array = new long[mLength];
@@ -116,6 +128,10 @@
 
         @FastNative
         private native void native_getValues(long nativeObject, long[] array);
+
+        @FastNative
+        private native boolean native_combineValues(long nativeObject, long[] array,
+                int[] indexMap);
     }
 
     private static final NativeAllocationRegistry sRegistry =
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 54e65e0..2bcc645 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -43,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Locale;
 
 /**
  * Reports power consumption values for various device activities. Reads values from an XML file.
@@ -315,6 +316,8 @@
 
     private static final Object sLock = new Object();
 
+    private int mCpuPowerBracketCount;
+
     @VisibleForTesting
     @UnsupportedAppUsage
     public PowerProfile(Context context) {
@@ -346,7 +349,6 @@
             sModemPowerProfile.clear();
             initLocked(context, xmlId);
         }
-
     }
 
     @GuardedBy("sLock")
@@ -450,6 +452,9 @@
     private static final String CPU_CLUSTER_POWER_COUNT = "cpu.cluster_power.cluster";
     private static final String CPU_CORE_SPEED_PREFIX = "cpu.core_speeds.cluster";
     private static final String CPU_CORE_POWER_PREFIX = "cpu.core_power.cluster";
+    private static final String CPU_POWER_BRACKETS_PREFIX = "cpu.power_brackets.cluster";
+
+    private static final int DEFAULT_CPU_POWER_BRACKET_NUMBER = 3;
 
     private void initCpuClusters() {
         if (sPowerArrayMap.containsKey(CPU_PER_CLUSTER_CORE_COUNT)) {
@@ -471,13 +476,104 @@
             mCpuClusters[0] = new CpuClusterKey(CPU_CORE_SPEED_PREFIX + 0,
                     CPU_CLUSTER_POWER_COUNT + 0, CPU_CORE_POWER_PREFIX + 0, numCpus);
         }
+
+        initCpuPowerBrackets(DEFAULT_CPU_POWER_BRACKET_NUMBER);
     }
 
-    public static class CpuClusterKey {
-        private final String freqKey;
-        private final String clusterPowerKey;
-        private final String corePowerKey;
-        private final int numCpus;
+    /**
+     * Parses or computes CPU power brackets: groups of states with similar power requirements.
+     */
+    @VisibleForTesting
+    public void initCpuPowerBrackets(int defaultCpuPowerBracketNumber) {
+        boolean anyBracketsSpecified = false;
+        boolean allBracketsSpecified = true;
+        for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
+            final int steps = getNumSpeedStepsInCpuCluster(cluster);
+            mCpuClusters[cluster].powerBrackets = new int[steps];
+            if (sPowerArrayMap.get(CPU_POWER_BRACKETS_PREFIX + cluster) != null) {
+                anyBracketsSpecified = true;
+            } else {
+                allBracketsSpecified = false;
+            }
+        }
+
+        if (anyBracketsSpecified && !allBracketsSpecified) {
+            throw new RuntimeException(
+                    "Power brackets should be specified for all clusters or no clusters");
+        }
+
+        mCpuPowerBracketCount = 0;
+        if (allBracketsSpecified) {
+            for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
+                final Double[] data = sPowerArrayMap.get(CPU_POWER_BRACKETS_PREFIX + cluster);
+                if (data.length != mCpuClusters[cluster].powerBrackets.length) {
+                    throw new RuntimeException(
+                            "Wrong number of items in " + CPU_POWER_BRACKETS_PREFIX + cluster);
+                }
+
+                for (int i = 0; i < data.length; i++) {
+                    final int bracket = (int) Math.round(data[i]);
+                    mCpuClusters[cluster].powerBrackets[i] = bracket;
+                    if (bracket > mCpuPowerBracketCount) {
+                        mCpuPowerBracketCount = bracket;
+                    }
+                }
+            }
+            mCpuPowerBracketCount++;
+        } else {
+            double minPower = Double.MAX_VALUE;
+            double maxPower = Double.MIN_VALUE;
+            int stateCount = 0;
+            for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
+                final int steps = getNumSpeedStepsInCpuCluster(cluster);
+                for (int step = 0; step < steps; step++) {
+                    final double power = getAveragePowerForCpuCore(cluster, step);
+                    if (power < minPower) {
+                        minPower = power;
+                    }
+                    if (power > maxPower) {
+                        maxPower = power;
+                    }
+                }
+                stateCount += steps;
+            }
+
+            if (stateCount <= defaultCpuPowerBracketNumber) {
+                mCpuPowerBracketCount = stateCount;
+                int bracket = 0;
+                for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
+                    final int steps = getNumSpeedStepsInCpuCluster(cluster);
+                    for (int step = 0; step < steps; step++) {
+                        mCpuClusters[cluster].powerBrackets[step] = bracket++;
+                    }
+                }
+            } else {
+                mCpuPowerBracketCount = defaultCpuPowerBracketNumber;
+                final double minLogPower = Math.log(minPower);
+                final double logBracket = (Math.log(maxPower) - minLogPower)
+                        / defaultCpuPowerBracketNumber;
+
+                for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
+                    final int steps = getNumSpeedStepsInCpuCluster(cluster);
+                    for (int step = 0; step < steps; step++) {
+                        final double power = getAveragePowerForCpuCore(cluster, step);
+                        int bracket = (int) ((Math.log(power) - minLogPower) / logBracket);
+                        if (bracket >= defaultCpuPowerBracketNumber) {
+                            bracket = defaultCpuPowerBracketNumber - 1;
+                        }
+                        mCpuClusters[cluster].powerBrackets[step] = bracket;
+                    }
+                }
+            }
+        }
+    }
+
+    private static class CpuClusterKey {
+        public final String freqKey;
+        public final String clusterPowerKey;
+        public final String corePowerKey;
+        public final int numCpus;
+        public int[] powerBrackets;
 
         private CpuClusterKey(String freqKey, String clusterPowerKey,
                 String corePowerKey, int numCpus) {
@@ -525,6 +621,57 @@
         return 0;
     }
 
+    /**
+     * Returns the number of CPU power brackets: groups of states with similar power requirements.
+     */
+    public int getCpuPowerBracketCount() {
+        return mCpuPowerBracketCount;
+    }
+
+    /**
+     * Description of a CPU power bracket: which cluster/frequency combinations are included.
+     */
+    public String getCpuPowerBracketDescription(int powerBracket) {
+        StringBuilder sb = new StringBuilder();
+        for (int cluster = 0; cluster < mCpuClusters.length; cluster++) {
+            int[] brackets = mCpuClusters[cluster].powerBrackets;
+            for (int step = 0; step < brackets.length; step++) {
+                if (brackets[step] == powerBracket) {
+                    if (sb.length() != 0) {
+                        sb.append(", ");
+                    }
+                    if (mCpuClusters.length > 1) {
+                        sb.append(cluster).append('/');
+                    }
+                    Double[] freqs = sPowerArrayMap.get(mCpuClusters[cluster].freqKey);
+                    if (freqs != null && step < freqs.length) {
+                        // Frequency in MHz
+                        sb.append(freqs[step].intValue() / 1000);
+                    }
+                    sb.append('(');
+                    sb.append(String.format(Locale.US, "%.1f",
+                            getAveragePowerForCpuCore(cluster, step)));
+                    sb.append(')');
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns the CPU power bracket corresponding to the specified cluster and frequency step
+     */
+    public int getPowerBracketForCpuCore(int cluster, int step) {
+        if (cluster >= 0
+                && cluster < mCpuClusters.length
+                && step >= 0
+                && step < mCpuClusters[cluster].powerBrackets.length) {
+            return mCpuClusters[cluster].powerBrackets[step];
+        }
+        return 0;
+    }
+
+
     private int mNumDisplays;
 
     private void initDisplays() {
diff --git a/core/java/com/android/internal/os/ZygoteConnectionConstants.java b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
index 0c1cd6d..fe9b992 100644
--- a/core/java/com/android/internal/os/ZygoteConnectionConstants.java
+++ b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
@@ -41,5 +41,5 @@
      * WARNING: This may trigger the watchdog in debug mode. However, to support
      *          wrapping on lower-end devices we do not have much choice.
      */
-    public static final int WRAPPED_PID_TIMEOUT_MILLIS = 30000;
+    public static final int WRAPPED_PID_TIMEOUT_MILLIS = 20000;
 }
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 527286cf0..a065e2b 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -287,7 +287,6 @@
         int dividerMax = isHorizontalDivision
                 ? mDisplayHeight
                 : mDisplayWidth;
-        int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
         int startPos = -mDividerSize;
         if (dockedSide == DOCKED_RIGHT) {
             startPos += mInsets.left;
@@ -308,8 +307,7 @@
                 addMinimizedTarget(isHorizontalDivision, dockedSide);
                 break;
         }
-        mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
-                SnapTarget.FLAG_DISMISS_END, 0.35f));
+        mTargets.add(new SnapTarget(dividerMax, dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
     }
 
     private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 9f21760..4cf0ba1 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -111,6 +111,7 @@
     private Icon mLargeIcon;
     private View mExpandButtonContainer;
     private ViewGroup mExpandButtonAndContentContainer;
+    private ViewGroup mExpandButtonContainerA11yContainer;
     private NotificationExpandButton mExpandButton;
     private MessagingLinearLayout mImageMessageContainer;
     private int mBadgeProtrusion;
@@ -234,6 +235,8 @@
         });
         mConversationText = findViewById(R.id.conversation_text);
         mExpandButtonContainer = findViewById(R.id.expand_button_container);
+        mExpandButtonContainerA11yContainer =
+                findViewById(R.id.expand_button_a11y_container);
         mConversationHeader = findViewById(R.id.conversation_header);
         mContentContainer = findViewById(R.id.notification_action_list_margin_target);
         mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
@@ -1091,7 +1094,7 @@
             newContainer = mExpandButtonAndContentContainer;
         } else {
             buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-            newContainer = this;
+            newContainer = mExpandButtonContainerA11yContainer;
         }
         mExpandButton.setExpanded(!mIsCollapsed);
 
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 9ee9b82..c08f264 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -18,6 +18,7 @@
 
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Insets;
 import android.graphics.Paint;
@@ -32,6 +33,7 @@
 import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.ISystemGestureExclusionListener;
 import android.view.InputDevice;
 import android.view.KeyEvent;
@@ -45,8 +47,6 @@
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
-import java.util.ArrayList;
-
 public class PointerLocationView extends View implements InputDeviceListener,
         PointerEventListener {
     private static final String TAG = "Pointer";
@@ -61,6 +61,9 @@
      */
     private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
 
+    // In case when it's in first time or no active pointer found, draw the empty state.
+    private static final PointerState EMPTY_POINTER_STATE = new PointerState();
+
     public static class PointerState {
         // Trace of previous points.
         private float[] mTraceX = new float[32];
@@ -90,8 +93,10 @@
         private float mBoundingBottom;
 
         // Position estimator.
-        private VelocityTracker.Estimator mEstimator = new VelocityTracker.Estimator();
-        private VelocityTracker.Estimator mAltEstimator = new VelocityTracker.Estimator();
+        private VelocityTracker.Estimator mEstimatorX = new VelocityTracker.Estimator();
+        private VelocityTracker.Estimator mAltEstimatorX = new VelocityTracker.Estimator();
+        private VelocityTracker.Estimator mEstimatorY = new VelocityTracker.Estimator();
+        private VelocityTracker.Estimator mAltEstimatorY = new VelocityTracker.Estimator();
 
         @UnsupportedAppUsage
         public PointerState() {
@@ -147,7 +152,7 @@
     private int mMaxNumPointers;
     private int mActivePointerId;
     @UnsupportedAppUsage
-    private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>();
+    private final SparseArray<PointerState> mPointers = new SparseArray<PointerState>();
     private final PointerCoords mTempCoords = new PointerCoords();
 
     private final Region mSystemGestureExclusion = new Region();
@@ -173,8 +178,6 @@
         mVC = ViewConfiguration.get(c);
         mTextPaint = new Paint();
         mTextPaint.setAntiAlias(true);
-        mTextPaint.setTextSize(10
-                * getResources().getDisplayMetrics().density);
         mTextPaint.setARGB(255, 0, 0, 0);
         mTextBackgroundPaint = new Paint();
         mTextBackgroundPaint.setAntiAlias(false);
@@ -186,20 +189,19 @@
         mPaint.setAntiAlias(true);
         mPaint.setARGB(255, 255, 255, 255);
         mPaint.setStyle(Paint.Style.STROKE);
-        mPaint.setStrokeWidth(2);
         mCurrentPointPaint = new Paint();
         mCurrentPointPaint.setAntiAlias(true);
         mCurrentPointPaint.setARGB(255, 255, 0, 0);
         mCurrentPointPaint.setStyle(Paint.Style.STROKE);
-        mCurrentPointPaint.setStrokeWidth(2);
         mTargetPaint = new Paint();
         mTargetPaint.setAntiAlias(false);
         mTargetPaint.setARGB(255, 0, 0, 192);
         mPathPaint = new Paint();
         mPathPaint.setAntiAlias(false);
         mPathPaint.setARGB(255, 0, 96, 255);
-        mPaint.setStyle(Paint.Style.STROKE);
-        mPaint.setStrokeWidth(1);
+        mPathPaint.setStyle(Paint.Style.STROKE);
+
+        configureDensityDependentFactors();
 
         mSystemGestureExclusionPaint = new Paint();
         mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
@@ -209,8 +211,6 @@
         mSystemGestureExclusionRejectedPaint.setARGB(25, 0, 0, 255);
         mSystemGestureExclusionRejectedPaint.setStyle(Paint.Style.FILL_AND_STROKE);
 
-        PointerState ps = new PointerState();
-        mPointers.add(ps);
         mActivePointerId = 0;
 
         mVelocity = VelocityTracker.obtain();
@@ -306,7 +306,7 @@
 
         // Pointer trace.
         for (int p = 0; p < NP; p++) {
-            final PointerState ps = mPointers.get(p);
+            final PointerState ps = mPointers.valueAt(p);
 
             // Draw path.
             final int N = ps.mTraceCount;
@@ -317,7 +317,7 @@
             for (int i=0; i < N; i++) {
                 float x = ps.mTraceX[i];
                 float y = ps.mTraceY[i];
-                if (Float.isNaN(x)) {
+                if (Float.isNaN(x) || Float.isNaN(y)) {
                     haveLast = false;
                     continue;
                 }
@@ -416,10 +416,6 @@
     }
 
     private void drawLabels(Canvas canvas) {
-        if (mActivePointerId < 0 || mActivePointerId >= mPointers.size()) {
-            return;
-        }
-
         final int w = getWidth() - mWaterfallInsets.left - mWaterfallInsets.right;
         final int itemW = w / 7;
         final int base = mHeaderPaddingTop - mTextMetrics.ascent + 1;
@@ -427,7 +423,7 @@
 
         canvas.save();
         canvas.translate(mWaterfallInsets.left, 0);
-        final PointerState ps = mPointers.get(mActivePointerId);
+        final PointerState ps = mPointers.get(mActivePointerId, EMPTY_POINTER_STATE);
 
         canvas.drawRect(0, mHeaderPaddingTop, itemW - 1, bottom, mTextBackgroundPaint);
         canvas.drawText(mText.clear()
@@ -598,18 +594,13 @@
     @Override
     public void onPointerEvent(MotionEvent event) {
         final int action = event.getAction();
-        int NP = mPointers.size();
 
         if (action == MotionEvent.ACTION_DOWN
                 || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
             final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
                     >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down
             if (action == MotionEvent.ACTION_DOWN) {
-                for (int p=0; p<NP; p++) {
-                    final PointerState ps = mPointers.get(p);
-                    ps.clearTrace();
-                    ps.mCurDown = false;
-                }
+                mPointers.clear();
                 mCurDown = true;
                 mCurNumPointers = 0;
                 mMaxNumPointers = 0;
@@ -625,18 +616,17 @@
             }
 
             final int id = event.getPointerId(index);
-            while (NP <= id) {
-                PointerState ps = new PointerState();
-                mPointers.add(ps);
-                NP++;
+            PointerState ps = mPointers.get(id);
+            if (ps == null) {
+                ps = new PointerState();
+                mPointers.put(id, ps);
             }
 
-            if (mActivePointerId < 0 || mActivePointerId >= NP
+            if (!mPointers.contains(mActivePointerId)
                     || !mPointers.get(mActivePointerId).mCurDown) {
                 mActivePointerId = id;
             }
 
-            final PointerState ps = mPointers.get(id);
             ps.mCurDown = true;
             InputDevice device = InputDevice.getDevice(event.getDeviceId());
             ps.mHasBoundingBox = device != null &&
@@ -679,11 +669,13 @@
                 ps.addTrace(coords.x, coords.y, true);
                 ps.mXVelocity = mVelocity.getXVelocity(id);
                 ps.mYVelocity = mVelocity.getYVelocity(id);
-                mVelocity.getEstimator(id, ps.mEstimator);
+                mVelocity.getEstimator(MotionEvent.AXIS_X, id, ps.mEstimatorX);
+                mVelocity.getEstimator(MotionEvent.AXIS_Y, id, ps.mEstimatorY);
                 if (mAltVelocity != null) {
                     ps.mAltXVelocity = mAltVelocity.getXVelocity(id);
                     ps.mAltYVelocity = mAltVelocity.getYVelocity(id);
-                    mAltVelocity.getEstimator(id, ps.mAltEstimator);
+                    mAltVelocity.getEstimator(MotionEvent.AXIS_X, id, ps.mAltEstimatorX);
+                    mAltVelocity.getEstimator(MotionEvent.AXIS_Y, id, ps.mAltEstimatorY);
                 }
                 ps.mToolType = event.getToolType(i);
 
@@ -703,13 +695,13 @@
                     >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP
 
             final int id = event.getPointerId(index);
-            if (id >= NP) {
-                Slog.wtf(TAG, "Got pointer ID out of bounds: id=" + id + " arraysize="
-                        + NP + " pointerindex=" + index
+            final PointerState ps = mPointers.get(id);
+            if (ps == null) {
+                Slog.wtf(TAG, "Could not find pointer id=" + id + " in mPointers map,"
+                        + " size=" + mPointers.size() + " pointerindex=" + index
                         + " action=0x" + Integer.toHexString(action));
                 return;
             }
-            final PointerState ps = mPointers.get(id);
             ps.mCurDown = false;
 
             if (action == MotionEvent.ACTION_UP
@@ -1012,4 +1004,19 @@
             }
         }
     };
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        configureDensityDependentFactors();
+    }
+
+    // Compute size by display density.
+    private void configureDensityDependentFactors() {
+        final float density = getResources().getDisplayMetrics().density;
+        mTextPaint.setTextSize(10 * density);
+        mPaint.setStrokeWidth(1 * density);
+        mCurrentPointPaint.setStrokeWidth(1 * density);
+        mPathPaint.setStrokeWidth(1 * density);
+    }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5498769..26d0be1 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -231,6 +231,8 @@
                 "android_hardware_input_InputWindowHandle.cpp",
                 "android_hardware_input_InputApplicationHandle.cpp",
                 "android_window_WindowInfosListener.cpp",
+                "android_window_ScreenCapture.cpp",
+                "jni_common.cpp",
             ],
 
             static_libs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 817b315..11cb64c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -211,6 +211,8 @@
 extern int register_com_android_internal_security_VerityUtils(JNIEnv* env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
 extern int register_android_window_WindowInfosListener(JNIEnv* env);
+extern int register_android_window_ScreenCapture(JNIEnv* env);
+extern int register_jni_common(JNIEnv* env);
 
 // Namespace for Android Runtime flags applied during boot time.
 static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
@@ -1647,6 +1649,8 @@
         REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader),
 
         REG_JNI(register_android_window_WindowInfosListener),
+        REG_JNI(register_android_window_ScreenCapture),
+        REG_JNI(register_jni_common),
 };
 
 /*
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index f24c666..746f88c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2179,7 +2179,7 @@
             break;
         }
 
-        nAudioMix->mCriteria.add(nCriterion);
+        nAudioMix->mCriteria.push_back(nCriterion);
         env->DeleteLocalRef(jCriterion);
     }
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e64b261..aefec6c 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -21,7 +21,6 @@
 #include <android-base/chrono_utils.h>
 #include <android/graphics/properties.h>
 #include <android/graphics/region.h>
-#include <android/gui/BnScreenCaptureListener.h>
 #include <android/gui/BnWindowInfosReportedListener.h>
 #include <android/hardware/display/IDeviceProductInfoConstants.h>
 #include <android/os/IInputConstants.h>
@@ -60,12 +59,12 @@
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 #include "core_jni_helpers.h"
+#include "jni_common.h"
 
 // ----------------------------------------------------------------------------
 
 namespace android {
 
-using gui::CaptureArgs;
 using gui::FocusRequest;
 
 static void doThrowNPE(JNIEnv* env) {
@@ -130,37 +129,6 @@
     jfieldID group;
 } gDisplayModeClassInfo;
 
-static struct {
-    jfieldID bottom;
-    jfieldID left;
-    jfieldID right;
-    jfieldID top;
-} gRectClassInfo;
-
-static struct {
-    jfieldID pixelFormat;
-    jfieldID sourceCrop;
-    jfieldID frameScaleX;
-    jfieldID frameScaleY;
-    jfieldID captureSecureLayers;
-    jfieldID allowProtected;
-    jfieldID uid;
-    jfieldID grayscale;
-} gCaptureArgsClassInfo;
-
-static struct {
-    jfieldID displayToken;
-    jfieldID width;
-    jfieldID height;
-    jfieldID useIdentityTransform;
-} gDisplayCaptureArgsClassInfo;
-
-static struct {
-    jfieldID layer;
-    jfieldID excludeLayers;
-    jfieldID childrenOnly;
-} gLayerCaptureArgsClassInfo;
-
 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
 void DeleteScreenshot(void* addr, void* context) {
     delete ((ScreenshotClient*) context);
@@ -220,16 +188,6 @@
 
 static struct {
     jclass clazz;
-    jmethodID builder;
-} gScreenshotHardwareBufferClassInfo;
-
-static struct {
-    jclass clazz;
-    jmethodID onScreenCaptureComplete;
-} gScreenCaptureListenerClassInfo;
-
-static struct {
-    jclass clazz;
     jmethodID ctor;
     jfieldID defaultMode;
     jfieldID allowGroupSwitching;
@@ -266,24 +224,6 @@
     jmethodID invokeReleaseCallback;
 } gInvokeReleaseCallback;
 
-class JNamedColorSpace {
-public:
-    // ColorSpace.Named.SRGB.ordinal() = 0;
-    static constexpr jint SRGB = 0;
-
-    // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
-    static constexpr jint DISPLAY_P3 = 7;
-};
-
-constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
-    switch (dataspace) {
-        case ui::Dataspace::DISPLAY_P3:
-            return JNamedColorSpace::DISPLAY_P3;
-        default:
-            return JNamedColorSpace::SRGB;
-    }
-}
-
 constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
     switch (colorMode) {
         case ui::ColorMode::DISPLAY_P3:
@@ -296,59 +236,6 @@
     }
 }
 
-class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener {
-public:
-    explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
-        env->GetJavaVM(&mVm);
-        screenCaptureListenerObject = env->NewGlobalRef(jobject);
-        LOG_ALWAYS_FATAL_IF(!screenCaptureListenerObject, "Failed to make global ref");
-    }
-
-    ~ScreenCaptureListenerWrapper() {
-        if (screenCaptureListenerObject) {
-            getenv()->DeleteGlobalRef(screenCaptureListenerObject);
-            screenCaptureListenerObject = nullptr;
-        }
-    }
-
-    binder::Status onScreenCaptureCompleted(
-            const gui::ScreenCaptureResults& captureResults) override {
-        JNIEnv* env = getenv();
-        if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) {
-            env->CallVoidMethod(screenCaptureListenerObject,
-                                gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
-            return binder::Status::ok();
-        }
-        captureResults.fenceResult.value()->waitForever("");
-        jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
-                env, captureResults.buffer->toAHardwareBuffer());
-        const jint namedColorSpace =
-                fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
-        jobject screenshotHardwareBuffer =
-                env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
-                                            gScreenshotHardwareBufferClassInfo.builder,
-                                            jhardwareBuffer, namedColorSpace,
-                                            captureResults.capturedSecureLayers,
-                                            captureResults.capturedHdrLayers);
-        env->CallVoidMethod(screenCaptureListenerObject,
-                            gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
-                            screenshotHardwareBuffer);
-        env->DeleteLocalRef(jhardwareBuffer);
-        env->DeleteLocalRef(screenshotHardwareBuffer);
-        return binder::Status::ok();
-    }
-
-private:
-    jobject screenCaptureListenerObject;
-    JavaVM* mVm;
-
-    JNIEnv* getenv() {
-        JNIEnv* env;
-        mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
-        return env;
-    }
-};
-
 class TransactionCommittedListenerWrapper {
 public:
     explicit TransactionCommittedListenerWrapper(JNIEnv* env, jobject object) {
@@ -494,102 +381,6 @@
     }
 }
 
-static Rect rectFromObj(JNIEnv* env, jobject rectObj) {
-    int left = env->GetIntField(rectObj, gRectClassInfo.left);
-    int top = env->GetIntField(rectObj, gRectClassInfo.top);
-    int right = env->GetIntField(rectObj, gRectClassInfo.right);
-    int bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
-    return Rect(left, top, right, bottom);
-}
-
-static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
-    captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
-            env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
-    captureArgs.sourceCrop =
-            rectFromObj(env,
-                        env->GetObjectField(captureArgsObject, gCaptureArgsClassInfo.sourceCrop));
-    captureArgs.frameScaleX =
-            env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleX);
-    captureArgs.frameScaleY =
-            env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleY);
-    captureArgs.captureSecureLayers =
-            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
-    captureArgs.allowProtected =
-            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.allowProtected);
-    captureArgs.uid = env->GetLongField(captureArgsObject, gCaptureArgsClassInfo.uid);
-    captureArgs.grayscale =
-            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.grayscale);
-}
-
-static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
-                                                       jobject displayCaptureArgsObject) {
-    DisplayCaptureArgs captureArgs;
-    getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
-
-    captureArgs.displayToken =
-            ibinderForJavaObject(env,
-                                 env->GetObjectField(displayCaptureArgsObject,
-                                                     gDisplayCaptureArgsClassInfo.displayToken));
-    captureArgs.width =
-            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
-    captureArgs.height =
-            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
-    captureArgs.useIdentityTransform =
-            env->GetBooleanField(displayCaptureArgsObject,
-                                 gDisplayCaptureArgsClassInfo.useIdentityTransform);
-    return captureArgs;
-}
-
-static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject,
-                                 jobject screenCaptureListenerObject) {
-    const DisplayCaptureArgs captureArgs =
-            displayCaptureArgsFromObject(env, displayCaptureArgsObject);
-
-    if (captureArgs.displayToken == NULL) {
-        return BAD_VALUE;
-    }
-
-    sp<IScreenCaptureListener> captureListener =
-            new ScreenCaptureListenerWrapper(env, screenCaptureListenerObject);
-    return ScreenshotClient::captureDisplay(captureArgs, captureListener);
-}
-
-static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
-                                jobject screenCaptureListenerObject) {
-    LayerCaptureArgs captureArgs;
-    getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
-    SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
-            env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
-    if (layer == nullptr) {
-        return BAD_VALUE;
-    }
-
-    captureArgs.layerHandle = layer->getHandle();
-    captureArgs.childrenOnly =
-            env->GetBooleanField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.childrenOnly);
-    jlongArray excludeObjectArray = reinterpret_cast<jlongArray>(
-            env->GetObjectField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.excludeLayers));
-    if (excludeObjectArray != NULL) {
-        const jsize len = env->GetArrayLength(excludeObjectArray);
-        captureArgs.excludeHandles.reserve(len);
-
-        const jlong* objects = env->GetLongArrayElements(excludeObjectArray, nullptr);
-        for (jsize i = 0; i < len; i++) {
-            auto excludeObject = reinterpret_cast<SurfaceControl *>(objects[i]);
-            if (excludeObject == nullptr) {
-                jniThrowNullPointerException(env, "Exclude layer is null");
-                return NULL;
-            }
-            captureArgs.excludeHandles.emplace(excludeObject->getHandle());
-        }
-        env->ReleaseLongArrayElements(excludeObjectArray, const_cast<jlong*>(objects), JNI_ABORT);
-    }
-
-    sp<IScreenCaptureListener> captureListener =
-            new ScreenCaptureListenerWrapper(env, screenCaptureListenerObject);
-    return ScreenshotClient::captureLayers(captureArgs, captureListener);
-}
-
 static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
     transaction->apply(sync);
@@ -664,12 +455,12 @@
 
     Rect source, dst;
     if (sourceObj != NULL) {
-        source = rectFromObj(env, sourceObj);
+        source = JNICommon::rectFromObj(env, sourceObj);
     } else {
         source.makeInvalid();
     }
     if (dstObj != NULL) {
-        dst = rectFromObj(env, dstObj);
+        dst = JNICommon::rectFromObj(env, dstObj);
     } else {
         dst.makeInvalid();
     }
@@ -1183,20 +974,6 @@
                           histogramComponent3);
 }
 
-static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
-        jboolean secure) {
-    ScopedUtfChars name(env, nameObj);
-    sp<IBinder> token(SurfaceComposerClient::createDisplay(
-            String8(name.c_str()), bool(secure)));
-    return javaObjectForIBinder(env, token);
-}
-
-static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
-    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    if (token == NULL) return;
-    SurfaceComposerClient::destroyDisplay(token);
-}
-
 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
         jlong transactionObj,
         jobject tokenObj, jlong nativeSurfaceObject) {
@@ -2210,10 +1987,6 @@
             (void*)nativeGetPhysicalDisplayIds },
     {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
             (void*)nativeGetPhysicalDisplayToken },
-    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
-            (void*)nativeCreateDisplay },
-    {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
-            (void*)nativeDestroyDisplay },
     {"nativeSetDisplaySurface", "(JLandroid/os/IBinder;J)V",
             (void*)nativeSetDisplaySurface },
     {"nativeSetDisplayLayerStack", "(JLandroid/os/IBinder;I)V",
@@ -2269,12 +2042,6 @@
             (void*)nativeGetProtectedContentSupport },
     {"nativeReparent", "(JJJ)V",
             (void*)nativeReparent },
-    {"nativeCaptureDisplay",
-            "(Landroid/view/SurfaceControl$DisplayCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
-            (void*)nativeCaptureDisplay },
-    {"nativeCaptureLayers",
-            "(Landroid/view/SurfaceControl$LayerCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
-            (void*)nativeCaptureLayers },
     {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
             (void*)nativeSetInputWindowInfo },
     {"nativeSetMetadata", "(JJILandroid/os/Parcel;)V",
@@ -2416,12 +2183,6 @@
             GetFieldIDOrDie(env, modeClazz, "presentationDeadlineNanos", "J");
     gDisplayModeClassInfo.group = GetFieldIDOrDie(env, modeClazz, "group", "I");
 
-    jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
-    gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
-    gRectClassInfo.left =   GetFieldIDOrDie(env, rectClazz, "left", "I");
-    gRectClassInfo.right =  GetFieldIDOrDie(env, rectClazz, "right", "I");
-    gRectClassInfo.top =    GetFieldIDOrDie(env, rectClazz, "top", "I");
-
     jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
     jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
             frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
@@ -2462,15 +2223,6 @@
             GetMethodIDOrDie(env, deviceProductInfoManufactureDateClazz, "<init>",
                              "(Ljava/lang/Integer;Ljava/lang/Integer;)V");
 
-    jclass screenshotGraphicsBufferClazz =
-            FindClassOrDie(env, "android/view/SurfaceControl$ScreenshotHardwareBuffer");
-    gScreenshotHardwareBufferClassInfo.clazz =
-            MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
-    gScreenshotHardwareBufferClassInfo.builder =
-            GetStaticMethodIDOrDie(env, screenshotGraphicsBufferClazz, "createFromNative",
-                                   "(Landroid/hardware/HardwareBuffer;IZZ)Landroid/view/"
-                                   "SurfaceControl$ScreenshotHardwareBuffer;");
-
     jclass displayedContentSampleClazz = FindClassOrDie(env,
             "android/hardware/display/DisplayedContentSample");
     gDisplayedContentSampleClassInfo.clazz = MakeGlobalRefOrDie(env, displayedContentSampleClazz);
@@ -2523,46 +2275,6 @@
     gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax =
             GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMax", "F");
 
-    jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
-    gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
-    gCaptureArgsClassInfo.sourceCrop =
-            GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
-    gCaptureArgsClassInfo.frameScaleX = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleX", "F");
-    gCaptureArgsClassInfo.frameScaleY = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleY", "F");
-    gCaptureArgsClassInfo.captureSecureLayers =
-            GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
-    gCaptureArgsClassInfo.allowProtected =
-            GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
-    gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
-    gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
-
-    jclass displayCaptureArgsClazz =
-            FindClassOrDie(env, "android/view/SurfaceControl$DisplayCaptureArgs");
-    gDisplayCaptureArgsClassInfo.displayToken =
-            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
-    gDisplayCaptureArgsClassInfo.width =
-            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
-    gDisplayCaptureArgsClassInfo.height =
-            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
-    gDisplayCaptureArgsClassInfo.useIdentityTransform =
-            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
-
-    jclass layerCaptureArgsClazz =
-            FindClassOrDie(env, "android/view/SurfaceControl$LayerCaptureArgs");
-    gLayerCaptureArgsClassInfo.layer =
-            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeLayer", "J");
-    gLayerCaptureArgsClassInfo.excludeLayers =
-            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeExcludeLayers", "[J");
-    gLayerCaptureArgsClassInfo.childrenOnly =
-            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");
-
-    jclass screenCaptureListenerClazz =
-            FindClassOrDie(env, "android/view/SurfaceControl$ScreenCaptureListener");
-    gScreenCaptureListenerClassInfo.clazz = MakeGlobalRefOrDie(env, screenCaptureListenerClazz);
-    gScreenCaptureListenerClassInfo.onScreenCaptureComplete =
-            GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete",
-                             "(Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;)V");
-
     jclass jankDataClazz =
                 FindClassOrDie(env, "android/view/SurfaceControl$JankData");
     gJankDataClassInfo.clazz = MakeGlobalRefOrDie(env, jankDataClazz);
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 46bd682..16b9f00 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -32,8 +32,7 @@
 static const int ACTIVE_POINTER_ID = -1;
 
 static struct {
-    jfieldID xCoeff;
-    jfieldID yCoeff;
+    jfieldID coeff;
     jfieldID degree;
     jfieldID confidence;
 } gEstimatorClassInfo;
@@ -47,28 +46,22 @@
 
     void clear();
     void addMovement(const MotionEvent* event);
+    // TODO(b/32830165): consider supporting an overload that supports computing velocity only for
+    // a subset of the supported axes.
     void computeCurrentVelocity(int32_t units, float maxVelocity);
-    void getVelocity(int32_t id, float* outVx, float* outVy);
-    bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator);
+    float getVelocity(int32_t axis, int32_t id);
+    bool getEstimator(int32_t axis, int32_t id, VelocityTracker::Estimator* outEstimator);
 
 private:
-    struct Velocity {
-        float vx, vy;
-    };
-
     VelocityTracker mVelocityTracker;
-    int32_t mActivePointerId;
-    BitSet32 mCalculatedIdBits;
-    Velocity mCalculatedVelocity[MAX_POINTERS];
+    VelocityTracker::ComputedVelocity mComputedVelocity;
 };
 
 VelocityTrackerState::VelocityTrackerState(const VelocityTracker::Strategy strategy)
-      : mVelocityTracker(strategy), mActivePointerId(-1) {}
+      : mVelocityTracker(strategy) {}
 
 void VelocityTrackerState::clear() {
     mVelocityTracker.clear();
-    mActivePointerId = -1;
-    mCalculatedIdBits.clear();
 }
 
 void VelocityTrackerState::addMovement(const MotionEvent* event) {
@@ -76,61 +69,20 @@
 }
 
 void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) {
-    BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits());
-    mCalculatedIdBits = idBits;
-
-    for (uint32_t index = 0; !idBits.isEmpty(); index++) {
-        uint32_t id = idBits.clearFirstMarkedBit();
-
-        float vx, vy;
-        mVelocityTracker.getVelocity(id, &vx, &vy);
-
-        vx = vx * units / 1000;
-        vy = vy * units / 1000;
-
-        if (vx > maxVelocity) {
-            vx = maxVelocity;
-        } else if (vx < -maxVelocity) {
-            vx = -maxVelocity;
-        }
-        if (vy > maxVelocity) {
-            vy = maxVelocity;
-        } else if (vy < -maxVelocity) {
-            vy = -maxVelocity;
-        }
-
-        Velocity& velocity = mCalculatedVelocity[index];
-        velocity.vx = vx;
-        velocity.vy = vy;
-    }
+    mComputedVelocity = mVelocityTracker.getComputedVelocity(units, maxVelocity);
 }
 
-void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) {
+float VelocityTrackerState::getVelocity(int32_t axis, int32_t id) {
     if (id == ACTIVE_POINTER_ID) {
         id = mVelocityTracker.getActivePointerId();
     }
 
-    float vx, vy;
-    if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) {
-        uint32_t index = mCalculatedIdBits.getIndexOfBit(id);
-        const Velocity& velocity = mCalculatedVelocity[index];
-        vx = velocity.vx;
-        vy = velocity.vy;
-    } else {
-        vx = 0;
-        vy = 0;
-    }
-
-    if (outVx) {
-        *outVx = vx;
-    }
-    if (outVy) {
-        *outVy = vy;
-    }
+    return mComputedVelocity.getVelocity(axis, id).value_or(0);
 }
 
-bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
-    return mVelocityTracker.getEstimator(id, outEstimator);
+bool VelocityTrackerState::getEstimator(int32_t axis, int32_t id,
+                                        VelocityTracker::Estimator* outEstimator) {
+    return mVelocityTracker.getEstimator(axis, id, outEstimator);
 }
 
 // Return a strategy enum from integer value.
@@ -177,37 +129,25 @@
     state->computeCurrentVelocity(units, maxVelocity);
 }
 
-static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
-        jlong ptr, jint id) {
+static jfloat android_view_VelocityTracker_nativeGetVelocity(JNIEnv* env, jclass clazz, jlong ptr,
+                                                             jint axis, jint id) {
     VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
-    float vx;
-    state->getVelocity(id, &vx, NULL);
-    return vx;
-}
-
-static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
-        jlong ptr, jint id) {
-    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
-    float vy;
-    state->getVelocity(id, NULL, &vy);
-    return vy;
+    return state->getVelocity(axis, id);
 }
 
 static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
-        jlong ptr, jint id, jobject outEstimatorObj) {
+                                                                jlong ptr, jint axis, jint id,
+                                                                jobject outEstimatorObj) {
     VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
     VelocityTracker::Estimator estimator;
-    bool result = state->getEstimator(id, &estimator);
 
-    jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
-            gEstimatorClassInfo.xCoeff));
-    jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
-            gEstimatorClassInfo.yCoeff));
+    bool result = state->getEstimator(axis, id, &estimator);
 
-    env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
-            estimator.xCoeff);
-    env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
-            estimator.yCoeff);
+    jfloatArray coeffObj =
+            jfloatArray(env->GetObjectField(outEstimatorObj, gEstimatorClassInfo.coeff));
+
+    env->SetFloatArrayRegion(coeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
+                             estimator.coeff);
     env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
     env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
     return result;
@@ -224,9 +164,8 @@
          (void*)android_view_VelocityTracker_nativeAddMovement},
         {"nativeComputeCurrentVelocity", "(JIF)V",
          (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity},
-        {"nativeGetXVelocity", "(JI)F", (void*)android_view_VelocityTracker_nativeGetXVelocity},
-        {"nativeGetYVelocity", "(JI)F", (void*)android_view_VelocityTracker_nativeGetYVelocity},
-        {"nativeGetEstimator", "(JILandroid/view/VelocityTracker$Estimator;)Z",
+        {"nativeGetVelocity", "(JII)F", (void*)android_view_VelocityTracker_nativeGetVelocity},
+        {"nativeGetEstimator", "(JIILandroid/view/VelocityTracker$Estimator;)Z",
          (void*)android_view_VelocityTracker_nativeGetEstimator},
 };
 
@@ -236,8 +175,7 @@
 
     jclass clazz = FindClassOrDie(env, "android/view/VelocityTracker$Estimator");
 
-    gEstimatorClassInfo.xCoeff = GetFieldIDOrDie(env, clazz, "xCoeff", "[F");
-    gEstimatorClassInfo.yCoeff = GetFieldIDOrDie(env, clazz, "yCoeff", "[F");
+    gEstimatorClassInfo.coeff = GetFieldIDOrDie(env, clazz, "coeff", "[F");
     gEstimatorClassInfo.degree = GetFieldIDOrDie(env, clazz, "degree", "I");
     gEstimatorClassInfo.confidence = GetFieldIDOrDie(env, clazz, "confidence", "F");
 
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
new file mode 100644
index 0000000..3bada15
--- /dev/null
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ScreenCapture"
+// #define LOG_NDEBUG 0
+
+#include <android/gui/BnScreenCaptureListener.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <ui/GraphicTypes.h>
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+#include "jni_common.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+using gui::CaptureArgs;
+
+static struct {
+    jfieldID pixelFormat;
+    jfieldID sourceCrop;
+    jfieldID frameScaleX;
+    jfieldID frameScaleY;
+    jfieldID captureSecureLayers;
+    jfieldID allowProtected;
+    jfieldID uid;
+    jfieldID grayscale;
+} gCaptureArgsClassInfo;
+
+static struct {
+    jfieldID displayToken;
+    jfieldID width;
+    jfieldID height;
+    jfieldID useIdentityTransform;
+} gDisplayCaptureArgsClassInfo;
+
+static struct {
+    jfieldID layer;
+    jfieldID excludeLayers;
+    jfieldID childrenOnly;
+} gLayerCaptureArgsClassInfo;
+
+static struct {
+    jclass clazz;
+    jmethodID onScreenCaptureComplete;
+} gScreenCaptureListenerClassInfo;
+
+static struct {
+    jclass clazz;
+    jmethodID builder;
+} gScreenshotHardwareBufferClassInfo;
+
+enum JNamedColorSpace : jint {
+    // ColorSpace.Named.SRGB.ordinal() = 0;
+    SRGB = 0,
+
+    // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
+    DISPLAY_P3 = 7,
+};
+
+constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
+    switch (dataspace) {
+        case ui::Dataspace::DISPLAY_P3:
+            return JNamedColorSpace::DISPLAY_P3;
+        default:
+            return JNamedColorSpace::SRGB;
+    }
+}
+
+static void checkAndClearException(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        ALOGE("An exception was thrown by callback '%s'.", methodName);
+        env->ExceptionClear();
+    }
+}
+
+class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener {
+public:
+    explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
+        env->GetJavaVM(&mVm);
+        mScreenCaptureListenerObject = env->NewGlobalRef(jobject);
+        LOG_ALWAYS_FATAL_IF(!mScreenCaptureListenerObject, "Failed to make global ref");
+    }
+
+    ~ScreenCaptureListenerWrapper() {
+        if (mScreenCaptureListenerObject) {
+            getenv()->DeleteGlobalRef(mScreenCaptureListenerObject);
+            mScreenCaptureListenerObject = nullptr;
+        }
+    }
+
+    binder::Status onScreenCaptureCompleted(
+            const gui::ScreenCaptureResults& captureResults) override {
+        JNIEnv* env = getenv();
+        if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) {
+            env->CallVoidMethod(mScreenCaptureListenerObject,
+                                gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
+            checkAndClearException(env, "onScreenCaptureComplete");
+            return binder::Status::ok();
+        }
+        captureResults.fenceResult.value()->waitForever(LOG_TAG);
+        jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+                env, captureResults.buffer->toAHardwareBuffer());
+        const jint namedColorSpace =
+                fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
+        jobject screenshotHardwareBuffer =
+                env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
+                                            gScreenshotHardwareBufferClassInfo.builder,
+                                            jhardwareBuffer, namedColorSpace,
+                                            captureResults.capturedSecureLayers,
+                                            captureResults.capturedHdrLayers);
+        checkAndClearException(env, "builder");
+        env->CallVoidMethod(mScreenCaptureListenerObject,
+                            gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
+                            screenshotHardwareBuffer);
+        checkAndClearException(env, "onScreenCaptureComplete");
+        env->DeleteLocalRef(jhardwareBuffer);
+        env->DeleteLocalRef(screenshotHardwareBuffer);
+        return binder::Status::ok();
+    }
+
+private:
+    jobject mScreenCaptureListenerObject;
+    JavaVM* mVm;
+
+    JNIEnv* getenv() {
+        JNIEnv* env;
+        if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+            if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+                LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+            }
+        }
+        return env;
+    }
+};
+
+static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
+    captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
+            env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
+    captureArgs.sourceCrop =
+            JNICommon::rectFromObj(env,
+                                   env->GetObjectField(captureArgsObject,
+                                                       gCaptureArgsClassInfo.sourceCrop));
+    captureArgs.frameScaleX =
+            env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleX);
+    captureArgs.frameScaleY =
+            env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleY);
+    captureArgs.captureSecureLayers =
+            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
+    captureArgs.allowProtected =
+            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.allowProtected);
+    captureArgs.uid = env->GetLongField(captureArgsObject, gCaptureArgsClassInfo.uid);
+    captureArgs.grayscale =
+            env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.grayscale);
+}
+
+static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
+                                                       jobject displayCaptureArgsObject) {
+    DisplayCaptureArgs captureArgs;
+    getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
+
+    captureArgs.displayToken =
+            ibinderForJavaObject(env,
+                                 env->GetObjectField(displayCaptureArgsObject,
+                                                     gDisplayCaptureArgsClassInfo.displayToken));
+    captureArgs.width =
+            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
+    captureArgs.height =
+            env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
+    captureArgs.useIdentityTransform =
+            env->GetBooleanField(displayCaptureArgsObject,
+                                 gDisplayCaptureArgsClassInfo.useIdentityTransform);
+    return captureArgs;
+}
+
+static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject,
+                                 jobject screenCaptureListenerObject) {
+    const DisplayCaptureArgs captureArgs =
+            displayCaptureArgsFromObject(env, displayCaptureArgsObject);
+
+    if (captureArgs.displayToken == nullptr) {
+        return BAD_VALUE;
+    }
+
+    sp<IScreenCaptureListener> captureListener =
+            sp<ScreenCaptureListenerWrapper>::make(env, screenCaptureListenerObject);
+    return ScreenshotClient::captureDisplay(captureArgs, captureListener);
+}
+
+static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
+                                jobject screenCaptureListenerObject) {
+    LayerCaptureArgs captureArgs;
+    getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
+    SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
+            env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
+    if (layer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    captureArgs.layerHandle = layer->getHandle();
+    captureArgs.childrenOnly =
+            env->GetBooleanField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.childrenOnly);
+
+    jlongArray excludeObjectArray = reinterpret_cast<jlongArray>(
+            env->GetObjectField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.excludeLayers));
+    if (excludeObjectArray != nullptr) {
+        ScopedLongArrayRO excludeArray(env, excludeObjectArray);
+        const jsize len = excludeArray.size();
+        captureArgs.excludeHandles.reserve(len);
+
+        for (jsize i = 0; i < len; i++) {
+            auto excludeObject = reinterpret_cast<SurfaceControl*>(excludeArray[i]);
+            if (excludeObject == nullptr) {
+                jniThrowNullPointerException(env, "Exclude layer is null");
+                return BAD_VALUE;
+            }
+            captureArgs.excludeHandles.emplace(excludeObject->getHandle());
+        }
+    }
+
+    sp<IScreenCaptureListener> captureListener =
+            sp<ScreenCaptureListenerWrapper>::make(env, screenCaptureListenerObject);
+    return ScreenshotClient::captureLayers(captureArgs, captureListener);
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod sScreenCaptureMethods[] = {
+        // clang-format off
+   {"nativeCaptureDisplay",
+            "(Landroid/window/ScreenCapture$DisplayCaptureArgs;Landroid/window/ScreenCapture$ScreenCaptureListener;)I",
+            (void*)nativeCaptureDisplay },
+    {"nativeCaptureLayers",
+            "(Landroid/window/ScreenCapture$LayerCaptureArgs;Landroid/window/ScreenCapture$ScreenCaptureListener;)I",
+            (void*)nativeCaptureLayers },
+        // clang-format on
+};
+
+int register_android_window_ScreenCapture(JNIEnv* env) {
+    int err = RegisterMethodsOrDie(env, "android/window/ScreenCapture", sScreenCaptureMethods,
+                                   NELEM(sScreenCaptureMethods));
+
+    jclass captureArgsClazz = FindClassOrDie(env, "android/window/ScreenCapture$CaptureArgs");
+    gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
+    gCaptureArgsClassInfo.sourceCrop =
+            GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
+    gCaptureArgsClassInfo.frameScaleX = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleX", "F");
+    gCaptureArgsClassInfo.frameScaleY = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleY", "F");
+    gCaptureArgsClassInfo.captureSecureLayers =
+            GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
+    gCaptureArgsClassInfo.allowProtected =
+            GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
+    gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
+    gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
+
+    jclass displayCaptureArgsClazz =
+            FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs");
+    gDisplayCaptureArgsClassInfo.displayToken =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
+    gDisplayCaptureArgsClassInfo.width =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
+    gDisplayCaptureArgsClassInfo.height =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
+    gDisplayCaptureArgsClassInfo.useIdentityTransform =
+            GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
+
+    jclass layerCaptureArgsClazz =
+            FindClassOrDie(env, "android/window/ScreenCapture$LayerCaptureArgs");
+    gLayerCaptureArgsClassInfo.layer =
+            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeLayer", "J");
+    gLayerCaptureArgsClassInfo.excludeLayers =
+            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeExcludeLayers", "[J");
+    gLayerCaptureArgsClassInfo.childrenOnly =
+            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");
+
+    jclass screenCaptureListenerClazz =
+            FindClassOrDie(env, "android/window/ScreenCapture$ScreenCaptureListener");
+    gScreenCaptureListenerClassInfo.clazz = MakeGlobalRefOrDie(env, screenCaptureListenerClazz);
+    gScreenCaptureListenerClassInfo.onScreenCaptureComplete =
+            GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete",
+                             "(Landroid/window/ScreenCapture$ScreenshotHardwareBuffer;)V");
+
+    jclass screenshotGraphicsBufferClazz =
+            FindClassOrDie(env, "android/window/ScreenCapture$ScreenshotHardwareBuffer");
+    gScreenshotHardwareBufferClassInfo.clazz =
+            MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
+    gScreenshotHardwareBufferClassInfo.builder =
+            GetStaticMethodIDOrDie(env, screenshotGraphicsBufferClazz, "createFromNative",
+                                   "(Landroid/hardware/HardwareBuffer;IZZ)Landroid/window/"
+                                   "ScreenCapture$ScreenshotHardwareBuffer;");
+
+    return err;
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index 5b946d5..a95b6e3 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -244,6 +244,38 @@
     std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
 }
 
+static jboolean native_combineValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
+                                                        jlongArray jarray, jintArray jindexMap) {
+    std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+    ScopedLongArrayRW scopedArray(env, jarray);
+    ScopedIntArrayRO scopedIndexMap(env, jindexMap);
+
+    const uint64_t *data = vector->data();
+    uint64_t *array = reinterpret_cast<uint64_t *>(scopedArray.get());
+    const uint8_t size = scopedArray.size();
+
+    for (int i = 0; i < size; i++) {
+        array[i] = 0;
+    }
+
+    bool nonZero = false;
+    for (int i = 0; i < vector->size(); i++) {
+        jint index = scopedIndexMap[i];
+        if (index < 0 || index >= size) {
+            jniThrowExceptionFmt(env, "java/lang/IndexOutOfBoundsException",
+                                 "Index %d is out of bounds: [0, %d]", index, size - 1);
+            return false;
+        }
+
+        if (data[i] != 0L) {
+            array[index] += data[i];
+            nonZero = true;
+        }
+    }
+
+    return nonZero;
+}
+
 static const JNINativeMethod g_LongArrayContainer_methods[] = {
         // @CriticalNative
         {"native_init", "(I)J", (void *)native_init_LongArrayContainer},
@@ -253,6 +285,8 @@
         {"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
         // @FastNative
         {"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
+        // @FastNative
+        {"native_combineValues", "(J[J[I)Z", (void *)native_combineValues_LongArrayContainer},
 };
 
 int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cbc3462..550259f 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1277,68 +1277,80 @@
   }
   closedir(dir);
 
-  // Prepare default dirs for user 0 as user 0 always exists.
-  int result = symlink("/data/data", "/data/user/0");
-  if (result != 0) {
-    fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
-  }
-  PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION,
-      AID_ROOT, AID_ROOT, fail_fn);
-
-  for (int i = 0; i < size; i += 3) {
-    std::string const & packageName = merged_data_info_list[i];
-    std::string const & volUuid  = merged_data_info_list[i + 1];
-    std::string const & inode = merged_data_info_list[i + 2];
-
-    std::string::size_type sz;
-    long long ceDataInode = std::stoll(inode, &sz);
-
-    std::string actualCePath, actualDePath;
-    if (volUuid.compare("null") != 0) {
-      // Volume that is stored in /mnt/expand
-      char volPath[PATH_MAX];
-      char volCePath[PATH_MAX];
-      char volDePath[PATH_MAX];
-      char volCeUserPath[PATH_MAX];
-      char volDeUserPath[PATH_MAX];
-
-      snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
-      snprintf(volCePath, PATH_MAX, "%s/user", volPath);
-      snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
-      snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
-      snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
-
-      PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
-      PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
-          fail_fn);
-      PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
-          fail_fn);
-
-      actualCePath = volCeUserPath;
-      actualDePath = volDeUserPath;
-    } else {
-      // Internal volume that stored in /data
-      char internalCeUserPath[PATH_MAX];
-      char internalDeUserPath[PATH_MAX];
-      snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
-      snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
-      // If it's not user 0, create /data/user/$USER.
-      if (userId == 0) {
-        actualCePath = internalLegacyCePath;
-      } else {
-        PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION,
-            AID_ROOT, AID_ROOT, fail_fn);
-        actualCePath = internalCeUserPath;
+  // No bind mounting of app data should occur in the case of a sandbox process since SDK sandboxes
+  // should not be able to read app data. Tmpfs was mounted however since a sandbox should not have
+  // access to app data.
+  appid_t appId = multiuser_get_app_id(uid);
+  bool isSdkSandboxProcess =
+          (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END);
+  if (!isSdkSandboxProcess) {
+      // Prepare default dirs for user 0 as user 0 always exists.
+      int result = symlink("/data/data", "/data/user/0");
+      if (result != 0) {
+          fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
       }
-      PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION,
-          AID_ROOT, AID_ROOT, fail_fn);
-      actualDePath = internalDeUserPath;
-    }
-    isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode,
-        actualCePath, actualDePath, fail_fn);
+      PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                             fail_fn);
+
+      for (int i = 0; i < size; i += 3) {
+          std::string const& packageName = merged_data_info_list[i];
+          std::string const& volUuid = merged_data_info_list[i + 1];
+          std::string const& inode = merged_data_info_list[i + 2];
+
+          std::string::size_type sz;
+          long long ceDataInode = std::stoll(inode, &sz);
+
+          std::string actualCePath, actualDePath;
+          if (volUuid.compare("null") != 0) {
+              // Volume that is stored in /mnt/expand
+              char volPath[PATH_MAX];
+              char volCePath[PATH_MAX];
+              char volDePath[PATH_MAX];
+              char volCeUserPath[PATH_MAX];
+              char volDeUserPath[PATH_MAX];
+
+              snprintf(volPath, PATH_MAX, "/mnt/expand/%s", volUuid.c_str());
+              snprintf(volCePath, PATH_MAX, "%s/user", volPath);
+              snprintf(volDePath, PATH_MAX, "%s/user_de", volPath);
+              snprintf(volCeUserPath, PATH_MAX, "%s/%d", volCePath, userId);
+              snprintf(volDeUserPath, PATH_MAX, "%s/%d", volDePath, userId);
+
+              PrepareDirIfNotPresent(volPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volCePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volDePath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+              PrepareDirIfNotPresent(volDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+                                     fail_fn);
+
+              actualCePath = volCeUserPath;
+              actualDePath = volDeUserPath;
+          } else {
+              // Internal volume that stored in /data
+              char internalCeUserPath[PATH_MAX];
+              char internalDeUserPath[PATH_MAX];
+              snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
+              snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
+              // If it's not user 0, create /data/user/$USER.
+              if (userId == 0) {
+                  actualCePath = internalLegacyCePath;
+              } else {
+                  PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT,
+                                         AID_ROOT, fail_fn);
+                  actualCePath = internalCeUserPath;
+              }
+              PrepareDirIfNotPresent(internalDeUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT,
+                                     AID_ROOT, fail_fn);
+              actualDePath = internalDeUserPath;
+          }
+          isolateAppDataPerPackage(userId, packageName, volUuid, ceDataInode, actualCePath,
+                                   actualDePath, fail_fn);
+      }
   }
+
   // We set the label AFTER everything is done, as we are applying
   // the file operations on tmpfs. If we set the label when we mount
   // tmpfs, SELinux will not happy as we are changing system_data_files.
@@ -1379,6 +1391,167 @@
   freecon(dataFileContext);
 }
 
+/**
+ * Without sdk sandbox data isolation, the sandbox could detect if another app is installed on the
+ * system by "touching" other data directories like /data/misc_ce/0/sdksandbox/com.whatsapp, similar
+ * to apps without app data isolation (see {@link #isolateAppData()}).
+ *
+ * To prevent this, tmpfs is mounted onto misc_ce and misc_de directories on all possible volumes in
+ * a separate mount namespace. The sandbox directory path is then created containing the name of the
+ * client app package associated with the sdk sandbox. The contents for this (sdk level storage and
+ * shared sdk storage) are bind mounted from the sandbox data mirror.
+ */
+static void isolateSdkSandboxData(JNIEnv* env, jobjectArray pkg_data_info_list, uid_t uid,
+                                  const char* process_name, jstring managed_nice_name,
+                                  fail_fn_t fail_fn) {
+    const userid_t userId = multiuser_get_user_id(uid);
+
+    int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+    // The sandbox should only have information of one associated client app (package, uuid, inode)
+    if (size != 3) {
+        fail_fn(CREATE_ERROR(
+                "Unable to isolate sandbox data, incorrect associated app information"));
+    }
+
+    auto extract_fn = [env, process_name, managed_nice_name,
+                       pkg_data_info_list](int info_list_idx) {
+        jstring jstr = (jstring)(env->GetObjectArrayElement(pkg_data_info_list, info_list_idx));
+        return ExtractJString(env, process_name, managed_nice_name, jstr).value();
+    };
+    std::string packageName = extract_fn(0);
+    std::string volUuid = extract_fn(1);
+
+    char internalCePath[PATH_MAX];
+    char internalDePath[PATH_MAX];
+    char externalPrivateMountPath[PATH_MAX];
+    snprintf(internalCePath, PATH_MAX, "/data/misc_ce");
+    snprintf(internalDePath, PATH_MAX, "/data/misc_de");
+    snprintf(externalPrivateMountPath, PATH_MAX, "/mnt/expand");
+
+    char ceUserPath[PATH_MAX];
+    char deUserPath[PATH_MAX];
+    if (volUuid != "null") {
+        snprintf(ceUserPath, PATH_MAX, "%s/%s/misc_ce/%d", externalPrivateMountPath,
+                 volUuid.c_str(), userId);
+        snprintf(deUserPath, PATH_MAX, "%s/%s/misc_de/%d", externalPrivateMountPath,
+                 volUuid.c_str(), userId);
+    } else {
+        snprintf(ceUserPath, PATH_MAX, "%s/%d", internalCePath, userId);
+        snprintf(deUserPath, PATH_MAX, "%s/%d", internalDePath, userId);
+    }
+
+    char ceSandboxPath[PATH_MAX];
+    char deSandboxPath[PATH_MAX];
+    snprintf(ceSandboxPath, PATH_MAX, "%s/sdksandbox", ceUserPath);
+    snprintf(deSandboxPath, PATH_MAX, "%s/sdksandbox", deUserPath);
+
+    // If the client app using the sandbox has been installed when the device is locked and the
+    // sandbox starts up when the device is locked, sandbox storage might not have been created.
+    // In that case, mount tmpfs for data isolation, but don't bind mount.
+    bool bindMountCeSandboxDataDirs = true;
+    bool bindMountDeSandboxDataDirs = true;
+    if (access(ceSandboxPath, F_OK) != 0) {
+        bindMountCeSandboxDataDirs = false;
+    }
+    if (access(deSandboxPath, F_OK) != 0) {
+        bindMountDeSandboxDataDirs = false;
+    }
+
+    char* context = nullptr;
+    char* userContext = nullptr;
+    char* sandboxContext = nullptr;
+    if (getfilecon(internalDePath, &context) < 0) {
+        fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", internalDePath, strerror(errno)));
+    }
+    if (bindMountDeSandboxDataDirs) {
+        if (getfilecon(deUserPath, &userContext) < 0) {
+            fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", deUserPath, strerror(errno)));
+        }
+        if (getfilecon(deSandboxPath, &sandboxContext) < 0) {
+            fail_fn(CREATE_ERROR("Unable to getfilecon on %s %s", deSandboxPath, strerror(errno)));
+        }
+    }
+
+    MountAppDataTmpFs(internalCePath, fail_fn);
+    MountAppDataTmpFs(internalDePath, fail_fn);
+
+    // Mount tmpfs on all external volumes
+    DIR* dir = opendir(externalPrivateMountPath);
+    if (dir == nullptr) {
+        fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+    }
+    struct dirent* ent;
+    while ((ent = readdir(dir))) {
+        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+        if (ent->d_type != DT_DIR) {
+            fail_fn(CREATE_ERROR("Unexpected type: %d %s", ent->d_type, ent->d_name));
+        }
+        auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+        auto externalCePath = StringPrintf("%s/misc_ce", volPath.c_str());
+        auto externalDePath = StringPrintf("%s/misc_de", volPath.c_str());
+
+        WaitUntilDirReady(externalCePath.c_str(), fail_fn);
+        MountAppDataTmpFs(externalCePath.c_str(), fail_fn);
+        WaitUntilDirReady(externalDePath.c_str(), fail_fn);
+        MountAppDataTmpFs(externalDePath.c_str(), fail_fn);
+    }
+    closedir(dir);
+
+    char mirrorCeSandboxPath[PATH_MAX];
+    char mirrorDeSandboxPath[PATH_MAX];
+    snprintf(mirrorCeSandboxPath, PATH_MAX, "/data_mirror/misc_ce/%s/%d/sdksandbox",
+             volUuid.c_str(), userId);
+    snprintf(mirrorDeSandboxPath, PATH_MAX, "/data_mirror/misc_de/%s/%d/sdksandbox",
+             volUuid.c_str(), userId);
+
+    if (bindMountCeSandboxDataDirs) {
+        PrepareDir(ceUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDir(ceSandboxPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        // TODO(b/231322885): Use inode numbers to find the correct app path when the device locked.
+        createAndMountAppData(packageName, packageName, mirrorCeSandboxPath, ceSandboxPath, fail_fn,
+                              true /*call_fail_fn*/);
+
+        relabelDir(ceSandboxPath, sandboxContext, fail_fn);
+        relabelDir(ceUserPath, userContext, fail_fn);
+    }
+    if (bindMountDeSandboxDataDirs) {
+        PrepareDir(deUserPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        PrepareDir(deSandboxPath, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
+        createAndMountAppData(packageName, packageName, mirrorDeSandboxPath, deSandboxPath, fail_fn,
+                              true /*call_fail_fn*/);
+
+        relabelDir(deSandboxPath, sandboxContext, fail_fn);
+        relabelDir(deUserPath, userContext, fail_fn);
+    }
+
+    // We set the label AFTER everything is done, as we are applying
+    // the file operations on tmpfs. If we set the label when we mount
+    // tmpfs, SELinux will not happy as we are changing system_data_files.
+    relabelDir(internalCePath, context, fail_fn);
+    relabelDir(internalDePath, context, fail_fn);
+
+    // Relabel CE and DE dirs under /mnt/expand
+    dir = opendir(externalPrivateMountPath);
+    if (dir == nullptr) {
+        fail_fn(CREATE_ERROR("Failed to opendir %s", externalPrivateMountPath));
+    }
+    while ((ent = readdir(dir))) {
+        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
+        auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
+        auto externalCePath = StringPrintf("%s/misc_ce", volPath.c_str());
+        auto externalDePath = StringPrintf("%s/misc_de", volPath.c_str());
+        relabelDir(externalCePath.c_str(), context, fail_fn);
+        relabelDir(externalDePath.c_str(), context, fail_fn);
+    }
+    closedir(dir);
+
+    if (bindMountDeSandboxDataDirs) {
+        freecon(sandboxContext);
+        freecon(userContext);
+    }
+    freecon(context);
+}
+
 static void insertPackagesToMergedList(JNIEnv* env,
   std::vector<std::string>& merged_data_info_list,
   jobjectArray data_info_list, const char* process_name,
@@ -1444,6 +1617,13 @@
   MountAppDataTmpFs(kCurProfileDirPath, fail_fn);
   MountAppDataTmpFs(kRefProfileDirPath, fail_fn);
 
+  // Sandbox processes do not have JIT profile, so no data needs to be bind mounted. However, it
+  // should still not have access to JIT profile, so tmpfs is mounted.
+  appid_t appId = multiuser_get_app_id(uid);
+  if (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END) {
+      return;
+  }
+
   // Create profile directory for this user.
   std::string actualCurUserProfile = StringPrintf("%s/%d", kCurProfileDirPath, user_id);
   PrepareDir(actualCurUserProfile, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);
@@ -1596,9 +1776,16 @@
     // Make sure app is running in its own mount namespace before isolating its data directories.
     ensureInAppMountNamespace(fail_fn);
 
-    // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
-    // mount all related packages separately.
+    // Isolate app data, jit profile and sandbox data directories by overlaying a tmpfs on those
+    // dirs and bind mount all related packages separately.
     if (mount_data_dirs) {
+        // Sdk sandbox data isolation does not need to occur for app processes since sepolicy
+        // prevents access to sandbox data anyway.
+        appid_t appId = multiuser_get_app_id(uid);
+        if (appId >= AID_SDK_SANDBOX_PROCESS_START && appId <= AID_SDK_SANDBOX_PROCESS_END) {
+            isolateSdkSandboxData(env, pkg_data_info_list, uid, process_name, managed_nice_name,
+                                  fail_fn);
+        }
         isolateAppData(env, pkg_data_info_list, allowlisted_data_info_list, uid, process_name,
                        managed_nice_name, fail_fn);
         isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
diff --git a/core/jni/jni_common.cpp b/core/jni/jni_common.cpp
new file mode 100644
index 0000000..8d376cf
--- /dev/null
+++ b/core/jni/jni_common.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "jni_common.h"
+
+#include <jni.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+
+#include "core_jni_helpers.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static struct {
+    jfieldID bottom;
+    jfieldID left;
+    jfieldID right;
+    jfieldID top;
+} gRectClassInfo;
+
+Rect JNICommon::rectFromObj(JNIEnv* env, jobject rectObj) {
+    int left = env->GetIntField(rectObj, gRectClassInfo.left);
+    int top = env->GetIntField(rectObj, gRectClassInfo.top);
+    int right = env->GetIntField(rectObj, gRectClassInfo.right);
+    int bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
+    return Rect(left, top, right, bottom);
+}
+
+int register_jni_common(JNIEnv* env) {
+    jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
+    gRectClassInfo.left = GetFieldIDOrDie(env, rectClazz, "left", "I");
+    gRectClassInfo.right = GetFieldIDOrDie(env, rectClazz, "right", "I");
+    gRectClassInfo.top = GetFieldIDOrDie(env, rectClazz, "top", "I");
+    return 0;
+}
+
+} // namespace android
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/core/jni/jni_common.h
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to core/jni/jni_common.h
index 1de740a..a2bf6fb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/core/jni/jni_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,16 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <jni.h>
 
-package com.android.systemui.shared.system;
+namespace android {
 
-import android.annotation.UserIdInt;
-import android.content.Context;
+class Rect;
 
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+class JNICommon {
+public:
+    static Rect rectFromObj(JNIEnv* env, jobject rectObj);
+};
+} // namespace android
\ No newline at end of file
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 57026d9..4bbfee2 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -61,7 +61,6 @@
 import "frameworks/base/core/proto/android/privacy.proto";
 import "frameworks/base/core/proto/android/section.proto";
 import "frameworks/base/proto/src/ipconnectivity.proto";
-import "packages/modules/Connectivity/framework/proto/netstats.proto";
 import "packages/modules/Permission/service/proto/role_service.proto";
 
 package android.os;
@@ -247,11 +246,7 @@
         (section).args = "fingerprint --proto --incident"
     ];
 
-    optional android.service.NetworkStatsServiceDumpProto netstats = 3001 [
-        (section).type = SECTION_DUMPSYS,
-        (section).args = "netstats --proto",
-        (section).userdebug_and_eng_only = true
-    ];
+    reserved 3001;
 
     optional android.providers.settings.SettingsServiceDumpProto settings = 3002 [
         (section).type = SECTION_DUMPSYS,
diff --git a/core/res/OWNERS b/core/res/OWNERS
index c54638a..22f40a1 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -36,8 +36,11 @@
 # Car
 per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
 
+# Device Idle
+per-file res/values/config_device_idle.xml = file:/apex/jobscheduler/OWNERS
+
 # Wear
-per-file res/*-watch/* = file:/platform/frameworks/opt/wear:/OWNERS
+per-file res/*-watch/* = file:/WEAR_OWNERS
 
 # PowerProfile
 per-file res/xml/power_profile.xml = file:/BATTERY_STATS_OWNERS
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 42fb4a2..ce8a904 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -89,45 +89,62 @@
         <include layout="@layout/notification_material_action_list" />
     </com.android.internal.widget.RemeasuringLinearLayout>
 
-    <!--This is dynamically placed between here and at the end of the layout. It starts here since
-        only FrameLayout layout params have gravity-->
+    <!--expand_button_a11y_container ensures talkback focus order is correct when view is expanded.
+    The -1px of marginTop and 1px of paddingTop make sure expand_button_a11y_container is prior to
+    its sibling view in accessibility focus order.
+    {see android.view.ViewGroup.addChildrenForAccessibility()}
+    expand_button_container will be moved under expand_button_and_content_container when collapsed,
+    this dynamic movement ensures message can flow under expand button when expanded-->
     <FrameLayout
-        android:id="@+id/expand_button_container"
-        android:layout_width="wrap_content"
+        android:id="@+id/expand_button_a11y_container"
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="end|top"
         android:clipChildren="false"
-        android:clipToPadding="false">
-        <!--This layout makes sure that we can nicely center the expand content in the
-            collapsed layout while the parent makes sure that we're never laid out bigger
-            than the messaging content.-->
-        <LinearLayout
-            android:id="@+id/expand_button_touch_container"
+        android:clipToPadding="false"
+        android:layout_marginTop="-1px"
+        android:paddingTop="1px"
+        >
+        <!--expand_button_container is dynamically placed between here and at the end of the
+        layout. It starts here since only FrameLayout layout params have gravity-->
+        <FrameLayout
+            android:id="@+id/expand_button_container"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/conversation_expand_button_height"
-            android:orientation="horizontal"
+            android:layout_height="match_parent"
             android:layout_gravity="end|top"
-            android:paddingEnd="0dp"
-            android:clipToPadding="false"
             android:clipChildren="false"
-            >
-            <!-- Images -->
-            <com.android.internal.widget.MessagingLinearLayout
-                android:id="@+id/conversation_image_message_container"
-                android:forceHasOverlappingRendering="false"
-                android:layout_width="40dp"
-                android:layout_height="40dp"
-                android:layout_marginStart="@dimen/conversation_image_start_margin"
-                android:spacing="0dp"
-                android:layout_gravity="center"
+            android:clipToPadding="false">
+            <!--expand_button_touch_container makes sure that we can nicely center the expand
+            content in the collapsed layout while the parent makes sure that we're never laid out
+            bigger than the messaging content.-->
+            <LinearLayout
+                android:id="@+id/expand_button_touch_container"
+                android:layout_width="wrap_content"
+                android:layout_height="@dimen/conversation_expand_button_height"
+                android:orientation="horizontal"
+                android:layout_gravity="end|top"
+                android:paddingEnd="0dp"
                 android:clipToPadding="false"
                 android:clipChildren="false"
-                />
-            <include layout="@layout/notification_expand_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                />
-        </LinearLayout>
+                >
+                <!-- Images -->
+                <com.android.internal.widget.MessagingLinearLayout
+                    android:id="@+id/conversation_image_message_container"
+                    android:forceHasOverlappingRendering="false"
+                    android:layout_width="40dp"
+                    android:layout_height="40dp"
+                    android:layout_marginStart="@dimen/conversation_image_start_margin"
+                    android:spacing="0dp"
+                    android:layout_gravity="center"
+                    android:clipToPadding="false"
+                    android:clipChildren="false"
+                    />
+                <include layout="@layout/notification_expand_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    />
+            </LinearLayout>
+        </FrameLayout>
     </FrameLayout>
 </com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 99e98f2d..9b997bf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Vingerafdrukhandeling is gekanselleer."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Vingerafdrukhandeling is deur gebruiker gekanselleer."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Te veel pogings. Probeer later weer."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Te veel pogings. Gebruik eerder skermslot."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probeer weer."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukke is geregistreer nie."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Besoek \'n verskaffer wat herstelwerk doen."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan nie jou gesigmodel skep nie. Probeer weer."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Te helder. Probeer sagter beligting."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probeer helderder beligting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Beweeg foon verder weg"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Beweeg foon nader"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Beweeg foon hoër op"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Foon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokluidsprekers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Oorfone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Stelsel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index efb6686..698bce4 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -106,8 +106,8 @@
     <string name="roamingText0" msgid="7793257871609854208">"በዝውውር ላይ አመላካች በርቷል"</string>
     <string name="roamingText1" msgid="5073028598334616445">"በዝውውር ላይ አመልካች ጠፍቷል"</string>
     <string name="roamingText2" msgid="2834048284153110598">"በዝውውር ላይ አመልካች ብልጭ ብልጭ ይላል"</string>
-    <string name="roamingText3" msgid="831690234035748988">"ከጎረቤት ውጪ"</string>
-    <string name="roamingText4" msgid="2171252529065590728">"ከህንፃ ውጪ"</string>
+    <string name="roamingText3" msgid="831690234035748988">"ከጎረቤት ውጭ"</string>
+    <string name="roamingText4" msgid="2171252529065590728">"ከህንፃ ውጭ"</string>
     <string name="roamingText5" msgid="4294671587635796641">"የዝውውር- ተመራጭ ስርዓት"</string>
     <string name="roamingText6" msgid="5536156746637992029">"ዝውውር- ዝግጁ የሆነ ስርዓት"</string>
     <string name="roamingText7" msgid="1783303085512907706">" የዝውውር- አጋር ስምምነት"</string>
@@ -428,7 +428,7 @@
     <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"ይህ መተግበሪያ ሁሉንም በእርስዎ ጡባዊ ላይ የተከማቹ የቀን መቁጠሪያ ክስተቶችን ማንበብ ወይም የእርስዎን የቀን መቁጠሪያ ውሂብ ማስቀመጥ ይችላል።"</string>
     <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"ይህ መተግበሪያ ሁሉንም በእርስዎ Android TV መሣሪያ ላይ የተከማቹ የቀን መቁጠሪያ ክስተቶችን ማንበብ ወይም የእርስዎን የቀን መቁጠሪያ ውሂብ ማስቀመጥ ይችላል።"</string>
     <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"ይህ መተግበሪያ ሁሉንም በእርስዎ ስልክ ላይ የተከማቹ የቀን መቁጠሪያ ክስተቶችን ማንበብ ወይም የእርስዎን የቀን መቁጠሪያ ውሂብ ማስቀመጥ ይችላል።"</string>
-    <string name="permlab_writeCalendar" msgid="6422137308329578076">"የቀን መቁጠሪያ ክስተቶችን ቀይር ወይም አክል እና ለእንግዶች ከባለቤቱ ዕውቅና ውጪ ላክ።"</string>
+    <string name="permlab_writeCalendar" msgid="6422137308329578076">"የቀን መቁጠሪያ ክስተቶችን ቀይር ወይም አክል እና ለእንግዶች ከባለቤቱ ዕውቅና ውጭ ላክ።"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ይህ መተግበሪያ በእርስዎ ጡባዊ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ይህ መተግበሪያ በእርስዎ Android TV መሣሪያ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
     <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ይህ መተግበሪያ በእርስዎ ስልክ ላይ የቀን መቁጠሪያ ክስተቶችን ሊያክል፣ ሊያስወግድ ወይም ሊለውጥ ይችላል። ይህ መተግበሪያ ከቀን መቁጠሪያ የመጡ መስለው የሚታዩ መልእክቶችን ሊልክ ወይም ባለቤቶቹን ሳያሳውቅ ክስተቶችን ሊለውጥ ይችላል።"</string>
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"የጣት አሻራ ስርዓተ ክወና ተትቷል።"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"የጣት አሻራ ክወና በተጠቃሚ ተሰርዟል።"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"በጣም ብዙ ሙከራዎች። በምትኩ የማያ ገጽ መቆለፊያን ይጠቀሙ።"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"እንደገና ይሞክሩ።"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ምንም የጣት አሻራዎች አልተመዘገቡም።"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"የጥገና አገልግሎት ሰጪን ይጎብኙ።"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"የመልክዎን ሞዴል መፍጠር አልተቻለም። እንደገና ይሞክሩ።"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ከልክ በላይ ፈካ ያለ። ይበልጥ ረጋ ያለ ብርሃን አጠቃቀምን ይሞክሩ።"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ከዚህ ፈካ ያለ ብርሃንን ይሞክሩ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ስልኩን ያርቁት"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ስልኩን ያቅርቡት"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ስልኩን ከፍ ወዳለ ቦታ ይውሰዱት"</string>
@@ -1163,7 +1163,7 @@
     <string name="dialog_alert_title" msgid="651856561974090712">"ትኩረት"</string>
     <string name="loading" msgid="3138021523725055037">"በመጫን ላይ…"</string>
     <string name="capital_on" msgid="2770685323900821829">"በ"</string>
-    <string name="capital_off" msgid="7443704171014626777">"ውጪ"</string>
+    <string name="capital_off" msgid="7443704171014626777">"ውጭ"</string>
     <string name="checked" msgid="9179896827054513119">"ምልክት ተደርጎበታል"</string>
     <string name="not_checked" msgid="7972320087569023342">"ምልክት አልተደረገበትም"</string>
     <string name="selected" msgid="6614607926197755875">"ተመርጧል"</string>
@@ -1476,7 +1476,7 @@
     <string name="permission_request_notification_title" msgid="1810025922441048273">"ፈቃድ ተጠይቋል"</string>
     <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">\n" ለ<xliff:g id="ACCOUNT">%s</xliff:g> መለያ ፈቃድ ተጠይቋል"</string>
     <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"ለመለያ <xliff:g id="ACCOUNT">%2$s</xliff:g>\nበ<xliff:g id="APP">%1$s</xliff:g> የተጠየቀ ፈቃድ።"</string>
-    <string name="forward_intent_to_owner" msgid="4620359037192871015">"ከስራ መገለጫዎ ውጪ ሆነው መተግበሪያ እየተጠቀሙ ነው"</string>
+    <string name="forward_intent_to_owner" msgid="4620359037192871015">"ከስራ መገለጫዎ ውጭ ሆነው መተግበሪያ እየተጠቀሙ ነው"</string>
     <string name="forward_intent_to_work" msgid="3620262405636021151">"ይህን መተግበሪያ በእርስዎ የስራ መገለጫ ላይ እየተጠቀሙበት ነው"</string>
     <string name="input_method_binding_label" msgid="1166731601721983656">"ግቤት ስልት"</string>
     <string name="sync_binding_label" msgid="469249309424662147">"አስምር"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ቴሌቪዥን"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ስልክ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"የትከል ድምፅ ማጉያዎች"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"ኤችዲኤምአይ"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"ኤችዲኤምአይ"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"የጆሮ ማዳመጫዎች"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"ዩ ኤስ ቢ"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ስርዓት"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 503b697..82fc943 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -609,8 +609,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"تم إلغاء تشغيل بصمة الإصبع."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"تم إلغاء تشغيل بصمة الإصبع بواسطة المستخدم."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"تم إجراء عدد كبير من المحاولات. أعد المحاولة لاحقًا."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"تم إجراء عدد كبير جدًا من المحاولات. عليك استخدام قفل الشاشة بدلاً من ذلك."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"أعد المحاولة."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ليست هناك بصمات إصبع مسجَّلة."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string>
@@ -639,7 +638,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"يُرجى التواصل مع مقدِّم خدمات إصلاح."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"يتعذّر إنشاء نموذج الوجه. يُرجى إعادة المحاولة."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ساطع للغاية. تجربة مستوى سطوع أقلّ."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"جرِّب زيادة الإضاءة."</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"يُرجى إبعاد الهاتف عنك."</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"يُرجى تقريب الهاتف منك."</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"يُرجى رفع الهاتف للأعلى."</string>
@@ -1615,7 +1615,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"التلفزيون"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"الهاتف"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"مكبرات صوت للإرساء"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"سماعات رأس"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"النظام"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index ce46419..93957e5 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ফিংগাৰপ্ৰিণ্ট কাৰ্য বাতিল কৰা হ’ল।"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ব্যৱহাৰকাৰীয়ে ফিংগাৰপ্ৰিণ্ট ক্ৰিয়া বাতিল কৰিছে।"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"অতি বেছিসংখ্যক প্ৰয়াস। ইয়াৰ সলনি স্ক্ৰীন লক ব্যৱহাৰ কৰক।"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"আকৌ চেষ্টা কৰক।"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনো ফিংগাৰপ্ৰিণ্ট যোগ কৰা নহ\'ল।"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"মেৰামতি সেৱা প্ৰদানকাৰী কোনো প্ৰতিষ্ঠানলৈ যাওক।"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"মুখাৱয়বৰ মডেল সৃষ্টি কৰিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"অতি উজ্জ্বল। ইয়াতকৈ কম পোহৰৰ উৎস ব্যৱহাৰ কৰক।"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"উজ্জ্বল পোহৰ থকা ঠাইলৈ গৈ চাওক"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ফ’নটো আৰু আঁতৰলৈ নিয়ক"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ফ’নটো ওচৰলৈ আনক"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ফ’নটো ওপৰলৈ নিয়ক"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"টিভি"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ফ\'ন"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ড\'ক স্পীকাৰসমূহ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"হেডফ\'নবোৰ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"ইউএছবি"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ছিষ্টেম"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 0e2fd3f..c4f3d75 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Barmaq izi əməliyyatı ləğv edildi."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Barmaq izi əməliyyatı istifadəçi tərəfindən ləğv edildi."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Cəhdlər çox oldu. Sonraya saxlayın."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Həddindən çox cəhd edilib. Əvəzində ekran kilidindən istifadə edin."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Yenidən cəhd edin."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Barmaq izi qeydə alınmayıb."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Təmir provayderini ziyarət edin."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Üz modelinizi yaratmaq olmur. Yenə cəhd edin."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Çox işıqlıdır. Daha az işıqlı şəkli sınayın."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Parlaq işıqdan istifadə edin"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonu uzaq tutun"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonu yaxına tutun"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonu yuxarı tutun"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dok spikerlər"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Qulaqlıq"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 05d100b..bf9c57b 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -606,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Radnja sa otiskom prsta je otkazana."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Korisnik je otkazao radnju sa otiskom prsta."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Previše pokušaja. Probajte ponovo kasnije."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Previše pokušaja. Koristite zaključavanje ekrana umesto toga."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probajte ponovo."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registrovan nijedan otisak prsta."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
@@ -636,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posetite dobavljača za popravke."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Pravljenje modela lica nije uspelo. Probajte ponovo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Previše je svetlo. Probajte sa slabijim osvetljenjem."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probajte sa jačim osvetljenjem"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Udaljite telefon"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Približite telefon"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Pomerite telefon nagore"</string>
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvučnici bazne stanice"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalice"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 511dfdc..1af3c7d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Аперацыя з адбіткамі пальцаў скасавана."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Аўтэнтыфікацыя па адбітках пальцаў скасавана карыстальнікам."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Занадта шмат спроб. Паспрабуйце яшчэ раз пазней."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Занадта шмат спроб. Скарыстайце блакіроўку экрана."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паўтарыце спробу."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Звярніцеся ў сэрвісны цэнтр."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Не ўдалося стварыць мадэль твару. Паўтарыце."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Занадта светла. Прыглушыце асвятленне."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Павялічце асвятленне"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Перамясціце тэлефон далей"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Перамясціце тэлефон бліжэй"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Перамясціце тэлефон вышэй"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ТБ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Тэлефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Дынамікі станцыi"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Навушнікі"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Сістэма"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8f5aa43c..4ae1f21 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Операцията за отпечатък е анулирана."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Операцията за удостоверяване чрез отпечатък бе анулирана от потребителя."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Твърде много опити. Пробвайте отново по-късно."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Твърде много опити. Вместо това използвайте опция за заключване на екрана."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Опитайте отново."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Няма регистрирани отпечатъци."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Посетете оторизиран сервиз."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Моделът на лицето ви не бе създаден. Опитайте пак."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Твърде светло е. Опитайте при по-слабо осветление."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Опитайте при по-силно осветление"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Отдалечете телефона"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Доближете телефона"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Преместете телефона по-високо"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевизор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Докинг станц.: Високогов."</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Слушалки"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Система"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 7beea9a..2aac0c9 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"আঙ্গুলের ছাপ অপারেশন বাতিল করা হয়েছে৷"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ব্যবহারকারী আঙ্গুলের ছাপের অপারেশনটি বাতিল করেছেন।"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"অনেকবার প্রচেষ্টা করা হয়েছে৷ পরে আবার চেষ্টা করুন৷"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"অনেকবার চেষ্টা করেছেন। পরিবর্তে স্ক্রিন লক ব্যবহার করুন।"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"আবার চেষ্টা করুন৷"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনও আঙ্গুলের ছাপ নথিভুক্ত করা হয়নি।"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"একজন মেরামতি মিস্ত্রির কাছে যান।"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"ফেস মডেল তৈরি করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"খুব উজ্জ্বল। আলো কমিয়ে চেষ্টা করে দেখুন।"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"আরও উজ্জ্বল আলো ব্যবহার করে দেখুন"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ফোন আরও দূরে নিয়ে যান"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ফোন আরও কাছে নিয়ে আসুন"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ফোন আরও উঁচুতে তুলুন"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"টিভি"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ফোন"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ডক স্পিকার"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"হেডফোন"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"সিস্টেম"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index f182ab4..3c87b0d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -606,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Radnja s otiskom prsta je otkazana."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Korisnik je otkazao radnju s otiskom prsta."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Previše pokušaja. Umjesto toga koristite zaključavanje ekrana."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Pokušajte ponovo."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije prijavljen nijedan otisak prsta."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
@@ -636,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posjetite pružaoca usluga za popravke."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nije moguće kreirati model lica. Pokušajte ponovo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Previše svijetlo. Probajte s blažim osvjetljenjem."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Pokušajte s jačim osvjetljenjem"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Odmaknite telefon"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Primaknite telefon"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Pomjerite telefon naviše"</string>
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvučnici priključne stanice"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalice"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e88bb55..317c004 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"S\'ha cancel·lat l\'operació d\'empremta digital."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"L\'usuari ha cancel·lat l\'operació d\'empremta digital."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"S\'han produït massa intents. Torna-ho a provar més tard."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Massa intents. Utilitza el bloqueig de pantalla."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Torna-ho a provar."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No s\'ha registrat cap empremta digital."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes digitals."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un proveïdor de reparacions."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"No es pot crear el model facial. Torna-ho a provar."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Massa brillant Prova una il·luminació més suau."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prova amb més il·luminació"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Allunya\'t del telèfon"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Apropa el telèfon"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Mou el telèfon més amunt"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televisor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telèfon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altaveus de la base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculars"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d1c4d76..cbd2df6 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operace otisku prstu byla zrušena."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Uživatel operaci s otiskem prstu zrušil."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Příliš mnoho pokusů. Zkuste to později."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Příliš mnoho pokusů. Použijte zámek obrazovky."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Zkuste to znovu."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nejsou zaregistrovány žádné otisky prstů."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Navštivte servis"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Model se nepodařilo vytvořit. Zkuste to znovu."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Je příliš světlo. Zmírněte osvětlení."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Přejděte na světlo"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Umístěte telefon dál"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Umístěte telefon blíž"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Umístěte telefon výš"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televize"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Reproduktory doku"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Sluchátka"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Systém"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 5191aea..083c42c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingeraftrykshandlingen blev annulleret."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingeraftrykshandlingen blev annulleret af brugeren."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Du har prøvet for mange gange. Prøv igen senere."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Du har brugt for mange forsøg. Brug skærmlåsen i stedet."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Prøv igen."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Få den repareret."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Din ansigtsmodel kan ikke oprettes. Prøv igen."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Der er for lyst. Prøv en mere dæmpet belysning."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prøv med mere belysning"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Flyt telefonen længere væk"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Flyt telefonen tættere på"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Løft telefonen højere op"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tv"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dockstationens højttalere"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hovedtelefoner"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b5af566..fc8eadaf 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerabdruckvorgang abgebrochen"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Vorgang der Fingerabdruckauthentifizierung vom Nutzer abgebrochen."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Zu viele Versuche, bitte später noch einmal versuchen"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Zu viele Versuche. Verwende stattdessen die Displaysperre."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Bitte versuche es noch einmal."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Keine Fingerabdrücke erfasst."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Suche einen Reparaturdienstleister auf."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kein Gesichtsmodell möglich. Versuche es erneut."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Zu hell. Schwächere Beleuchtung ausprobieren."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probiere es mit einer helleren Beleuchtung"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Bewege das Smartphone weiter weg"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Bewege das Smartphone näher heran"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Bewege das Smartphone nach oben"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock-Lautsprecher"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kopfhörer"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 72290963..c76b2b0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Η λειτουργία δακτυλικού αποτυπώματος ακυρώθηκε."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Η λειτουργία δακτυλικού αποτυπώματος ακυρώθηκε από τον χρήστη."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Υπερβολικά πολλές προσπάθειες. Χρησιμοποιήστε εναλλακτικά το κλείδωμα οθόνης."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Δοκιμάστε ξανά."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Δεν έχουν καταχωριστεί δακτυλικά αποτυπώματα."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Επισκεφτείτε έναν πάροχο υπηρεσιών επισκευής."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Αδύν. η δημιουρ. του μοντ. προσώπ. Δοκιμάστε ξανά."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Υπερβολικά έντονος φωτισμός. Δοκιμάστε πιο ήπιο."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Δοκιμάστε με περισσότερο φως"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Απομακρύνετε περισσότερο το τηλέφωνο"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Φέρτε πιο κοντά το τηλέφωνό σας"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Μετακινήστε το τηλέφωνο πιο ψηλά"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Τηλεόραση"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Τηλέφωνο"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Ηχεία βάσης σύνδεσης"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ακουστικά"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Σύστημα"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index f0980bd..8591467 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -634,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1610,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 5907d88..08097a5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -634,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1610,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ebe3a4e..bf82587 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -634,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1610,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 5d9c8a2..110e68f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -634,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visit a repair provider."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Can’t create your face model. Try again."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Too bright. Try gentler lighting."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Try brighter lighting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Move phone further away"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Move phone closer"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Move phone higher"</string>
@@ -1610,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Phone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dock speakers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphones"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 3920362..ddb93a8 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -634,7 +634,7 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‏‏‏‎Visit a repair provider.‎‏‎‎‏‎"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎Can’t create your face model. Try again.‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎Too bright. Try gentler lighting.‎‏‎‎‏‎"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎Try brighter lighting‎‏‎‎‏‎"</string>
+    <string name="face_acquired_too_dark" msgid="8539853432479385326">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎Not enough light‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_close" msgid="4453646176196302462">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎Move phone farther away‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎Move phone closer‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎Move phone higher‎‏‎‎‏‎"</string>
@@ -1610,7 +1610,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎TV‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎Phone‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‏‎Dock speakers‎‏‎‎‏‎"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎HDMI‎‏‎‎‏‎"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎HDMI‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎Headphones‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎USB‎‏‎‎‏‎"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‏‎System‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 575476d..933ccfb 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -46,6 +46,7 @@
     <string name="needPuk2" msgid="7032612093451537186">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Error; habilita el bloqueo de SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más antes de que se bloquee la tarjeta SIM.</item>
       <item quantity="one">Tienes <xliff:g id="NUMBER_0">%d</xliff:g> un intento más antes de que se bloquee la tarjeta SIM.</item>
     </plurals>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"El almacenamiento del reloj está completo. Elimina algunos archivos para liberar espacio."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"El almacenamiento del dispositivo Android TV está lleno. Borra algunos archivos para liberar espacio."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Se instaló la autoridad certificadora}other{Se instalaron las autoridades certificadoras}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Se instaló la autoridad certificadora}many{Se instalaron las autoridades certificadoras}other{Se instalaron las autoridades certificadoras}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por un tercero desconocido"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Por parte de tu administrador del perfil de trabajo"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Usa esta opción en la mayoría de los casos. Te permite realizar un seguimiento del progreso del informe, ingresar más detalles acerca del problema y tomar capturas de pantalla. Es posible que se omitan secciones menos usadas cuyos informes demoran más en completarse."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Usa esta opción para reducir al mínimo la interferencia del sistema cuando tu dispositivo no responde o funciona muy lento, o cuando necesitas todas las secciones del informe. No permite ingresar más detalles ni tomar capturas de pantalla adicionales."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Se tomará una captura de pantalla para el informe de errores en # segundo.}other{Se tomará una captura de pantalla para el informe de errores en # segundos.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Se tomará una captura de pantalla para el informe de errores en # segundo.}many{Se tomará una captura de pantalla para el informe de errores en # segundos.}other{Se tomará una captura de pantalla para el informe de errores en # segundos.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se tomó la captura de pantalla con el informe de errores"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se pudo tomar la captura de pantalla con el informe de errores"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Se canceló la operación de huella dactilar."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"El usuario canceló la operación de huella dactilar."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiados intentos. Utiliza el bloqueo de pantalla en su lugar."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se registraron huellas digitales."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas dactilares."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Consulta a un proveedor de reparaciones."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"No se puede crear modelo de rostro. Reinténtalo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Demasiado brillante. Prueba con menos iluminación."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prueba con más iluminación"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Aleja el teléfono un poco más"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Acerca el teléfono"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Mueve el teléfono hacia arriba"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> desea activar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el dispositivo."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"Hace 1 mes."</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Anterior a 1 mes atrás"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último # día}other{Últimos # días}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último # día}many{Últimos # días}other{Últimos # días}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Último mes"</string>
     <string name="older" msgid="1645159827884647400">"Antiguos"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"en <xliff:g id="COUNT">%d</xliff:g> h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"en <xliff:g id="COUNT">%d</xliff:g> d"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"en <xliff:g id="COUNT">%d</xliff:g> años"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}other{Hace # minutos}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}other{Hace # horas}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}other{Hace # días}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}other{Hace # años}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minutos}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}other{# horas}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}other{# días}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}other{# años}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}many{Hace # minutos}other{Hace # minutos}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}many{Hace # horas}other{Hace # horas}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}many{Hace # días}other{Hace # días}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}many{Hace # años}other{Hace # años}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}many{# días}other{# días}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}many{# años}other{# años}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problemas de video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"No es posible transmitir este video al dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"No se puede reproducir el video."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"desactivado"</string>
     <string name="selected" msgid="6614607926197755875">"seleccionado"</string>
     <string name="not_selected" msgid="410652016565864475">"no seleccionado"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Una estrella de {max}}other{# estrellas de {max}}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Una estrella de {max}}many{# estrellas de {max}}other{# estrellas de {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"en curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar la acción mediante"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
     <string name="no_matches" msgid="6472699895759164599">"Sin coincidencias"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Buscar en la página"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}other{# de {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}many{# de {total}}other{# de {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Listo"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamiento compartido…"</string>
     <string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Dispositivo"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altavoces del conector"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculares"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por un minuto (hasta {formattedTime})}other{Por # minutos (hasta {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta {formattedTime})}other{Durante # min (hasta {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta {formattedTime})}other{Durante # horas (hasta {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta {formattedTime})}other{Durante # h (hasta {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante un minuto}other{Durante # minutos}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}other{Durante # min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}other{Durante # horas}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}other{Durante # h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por un minuto (hasta {formattedTime})}many{Por # minutos (hasta {formattedTime})}other{Por # minutos (hasta {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta {formattedTime})}many{Durante # min (hasta {formattedTime})}other{Durante # min (hasta {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta {formattedTime})}many{Durante # horas (hasta {formattedTime})}other{Durante # horas (hasta {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta {formattedTime})}many{Durante # h (hasta {formattedTime})}other{Durante # h (hasta {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante un minuto}many{Durante # minutos}other{Durante # minutos}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}many{Durante # min}other{Durante # min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}many{Durante # horas}other{Durante # horas}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}many{Durante # h}other{Durante # h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hasta la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Hasta la hora <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Guardar para Autocompletar"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"El contenido no puede autocompletarse"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"No hay sugerencias de Autocompletar"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Una sugerencia de autocompletar}other{# sugerencias de autocompletar}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Una sugerencia de autocompletar}many{# sugerencias de autocompletar}other{# sugerencias de autocompletar}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"¿Quieres guardar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"¿Quieres guardar la <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"¿Quieres guardar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"La conexión Bluetooth permanecerá activa durante el modo de avión"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}other{{file_name} y # archivos más}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}many{{file_name} y # archivos más}other{{file_name} y # archivos más}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"No hay personas recomendadas con quienes compartir"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Aunque no se le otorgó permiso de grabación a esta app, puede capturar audio con este dispositivo USB."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f1b4bdc..9795e23 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -46,6 +46,7 @@
     <string name="needPuk2" msgid="7032612093451537186">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Error, habilitar bloqueo de SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos para bloquear la tarjeta SIM.</item>
       <item quantity="one">Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para bloquear la tarjeta SIM.</item>
     </plurals>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"El almacenamiento del reloj está lleno. Elimina algunos archivos para liberar espacio."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"El espacio de almacenamiento de tu dispositivo Android TV está lleno. Elimina algunos archivos para liberar espacio."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridad de certificación instalada}other{Autoridades de certificación instaladas}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridad de certificación instalada}many{Autoridades de certificación instaladas}other{Autoridades de certificación instaladas}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por un tercero desconocido"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Por el administrador de tu perfil de trabajo"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Usa esta opción en la mayoría de los casos. Te permite realizar un seguimiento del progreso del informe, introducir más información sobre el problema y hacer capturas de pantalla. Es posible que se omitan algunas secciones menos utilizadas y que requieran más tiempo."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Informe completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utiliza esta opción para que la interferencia del sistema sea mínima cuando el dispositivo no responda o funcione demasiado lento, o bien cuando necesites todas las secciones del informe. No permite introducir más detalles ni hacer más capturas de pantalla."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{La captura de pantalla para el informe de errores se hará en # segundo.}other{La captura de pantalla para el informe de errores se hará en # segundos.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{La captura de pantalla para el informe de errores se hará en # segundo.}many{La captura de pantalla para el informe de errores se hará en # segundos.}other{La captura de pantalla para el informe de errores se hará en # segundos.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Se ha hecho la captura de pantalla con el informe de errores"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"No se ha podido hacer la captura de pantalla con el informe de errores"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo Silencio"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Se ha cancelado la operación de huella digital."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"El usuario ha cancelado la operación de huella digital."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiados intentos. Usa el bloqueo de pantalla."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se ha registrado ninguna huella digital."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un proveedor de reparaciones."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"No se puede crear tu modelo. Inténtalo de nuevo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Hay demasiada luz. Busca un sitio menos iluminado."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prueba en un lugar con más luz"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Aleja el teléfono"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Acerca el teléfono"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Sube el teléfono"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"Hace un mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Hace más de un mes"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último día (#)}other{Últimos # días}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Último día (#)}many{Últimos # días}other{Últimos # días}}"</string>
     <string name="last_month" msgid="1528906781083518683">"El mes pasado"</string>
     <string name="older" msgid="1645159827884647400">"Anterior"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"en <xliff:g id="COUNT">%d</xliff:g>h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"en <xliff:g id="COUNT">%d</xliff:g> d"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"en <xliff:g id="COUNT">%d</xliff:g>a"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}other{Hace # minutos}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}other{Hace # horas}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}other{Hace # días}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}other{Hace # años}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minutos}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}other{# horas}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}other{# días}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}other{# años}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Hace # minuto}many{Hace # minutos}other{Hace # minutos}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Hace # hora}many{Hace # horas}other{Hace # horas}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Hace # día}many{Hace # días}other{Hace # días}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Hace # año}many{Hace # años}other{Hace # años}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# día}many{# días}other{# días}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# año}many{# años}other{# años}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Incidencias con el vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo no se puede transmitir al dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"No se puede reproducir el vídeo."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"no seleccionado"</string>
     <string name="selected" msgid="6614607926197755875">"seleccionado"</string>
     <string name="not_selected" msgid="410652016565864475">"no seleccionado"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Una estrella de {max}}other{# estrellas de {max}}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Una estrella de {max}}many{# estrellas de {max}}other{# estrellas de {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"en curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar acción utilizando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Saltar"</string>
     <string name="no_matches" msgid="6472699895759164599">"No hay coincidencias."</string>
     <string name="find_on_page" msgid="5400537367077438198">"Buscar en la página"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}other{# de {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# coincidencia}many{# de {total}}other{# de {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Hecho"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Borrando almacenamiento compartido…"</string>
     <string name="share" msgid="4157615043345227321">"Compartir"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Teléfono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altavoces de la base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculares"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano. Si estás usando una aplicación, podrá acceder a datos, pero con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante un minuto (hasta las {formattedTime})}other{Durante # minutos (hasta las {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta las {formattedTime})}other{Durante # min (hasta las {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta las {formattedTime})}other{Durante # horas (hasta las {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta las {formattedTime})}other{Durante # h (hasta las {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante 1 minuto}other{Durante # minutos}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}other{Durante # min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}other{Durante # horas}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}other{Durante # h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante un minuto (hasta las {formattedTime})}many{Durante # minutos (hasta las {formattedTime})}other{Durante # minutos (hasta las {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (hasta las {formattedTime})}many{Durante # min (hasta las {formattedTime})}other{Durante # min (hasta las {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (hasta las {formattedTime})}many{Durante # horas (hasta las {formattedTime})}other{Durante # horas (hasta las {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (hasta las {formattedTime})}many{Durante # h (hasta las {formattedTime})}other{Durante # h (hasta las {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante 1 minuto}many{Durante # minutos}other{Durante # minutos}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}many{Durante # min}other{Durante # min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}many{Durante # horas}other{Durante # horas}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}many{Durante # h}other{Durante # h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hasta <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Guardar en la función Autocompletar"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"El contenido no se puede autocompletar"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"No hay sugerencias de Autocompletar"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 sugerencia de Autocompletar}other{# sugerencias de Autocompletar}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 sugerencia de Autocompletar}many{# sugerencias de Autocompletar}other{# sugerencias de Autocompletar}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"¿Guardar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"¿Guardar <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"¿Guardar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"El Bluetooth seguirá activado en el modo Avión"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}other{{file_name} y # archivos más}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} y # archivo más}many{{file_name} y # archivos más}other{{file_name} y # archivos más}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"No hay sugerencias de personas con las que compartir"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicaciones"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicación no tiene permiso para grabar, pero podría capturar audio con este dispositivo USB."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8b85348..fe7549e 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Sõrmejälje toiming tühistati."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Kasutaja tühistas sõrmejälje kasutamise."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Liiga palju katseid. Proovige hiljem uuesti."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Liiga palju katseid. Kasutage selle asemel ekraanilukku."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Proovige uuesti."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Külastage remonditeenuse pakkujat."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Teie näomudelit ei saa luua. Proovige uuesti."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Liiga ere. Proovige hämaramat valgust."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Proovige parema valgustusega kohas"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Liigutage telefoni kaugemale"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Liigutage telefoni lähemale"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Liigutage telefoni kõrgemale"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Teler"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Doki kõlarid"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kõrvaklapid"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Süsteem"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 45cfaf1..7f424eb 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Hatz-markaren eragiketa bertan behera utzi da."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Erabiltzaileak bertan behera utzi du hatz-marka bidezko eragiketa."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Saiakera gehiegi egin dira. Erabili pantailaren blokeoa."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Saiatu berriro."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ez da erregistratu hatz-markarik."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Jarri harremanetan konponketak egiten dituen hornitzaile batekin."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ezin da sortu aurpegi-eredua. Saiatu berriro."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Argi gehiegi dago. Joan toki ilunago batera."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Erabili argi gehiago"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Urrundu telefonoa"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Hurbildu telefonoa"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Igo telefonoa"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Telebista"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefonoa"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Konektatu bozgorailuak oinarrira"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Entzungailuak"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index df5bca5..83821a3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"عملکرد اثر انگشت لغو شد."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"کاربر عملیات اثر انگشت را لغو کرد"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"تلاش‌های زیادی انجام شده است. بعداً دوباره امتحان کنید."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"تلاش‌های بیش‌ازحد. حالا از قفل صفحه استفاده کنید."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"دوباره امتحان کنید."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"اثر انگشتی ثبت نشده است."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"به ارائه‌دهنده خدمات تعمیر مراجعه کنید."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"مدل چهره ایجاد نشد. دوباره امتحان کنید."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"خیلی روشن است. روشنایی‌اش را ملایم‌تر کنید."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"نور را بیشتر کنید"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"تلفن را دورتر ببرید"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"تلفن را نزدیک‌تر بیاورید"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"تلفن را بالاتر ببرید"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"تلویزیون"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"تلفن"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"بلندگوهای جایگاه"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"هدفون‌ها"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"سیستم"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 375d7af..8798ffc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Sormenjälkitoiminto peruutettiin."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Käyttäjä peruutti sormenjälkitoiminnon."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Liian monta yritystä. Käytä näytön lukituksen avaustapaa."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Yritä uudelleen."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Sormenjälkiä ei ole otettu käyttöön."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Ota yhteys korjauspalveluun."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kasvomallia ei voi luoda. Yritä uudelleen."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Liian kirkasta. Kokeile pehmeämpää valaistusta."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Kokeile kirkkaampaa valaistusta"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Vie puhelin kauemmas"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Tuo puhelin lähemmäs"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Siirrä puhelinta ylemmäs"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Puhelin"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Telineen kaiuttimet"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kuulokkeet"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Järjestelmä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index baf6f695..87861ae 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -47,6 +47,7 @@
     <string name="enablePin" msgid="2543771964137091212">"Opération infructueuse. Activez le verrouillage SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
       <item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM soit verrouillée.</item>
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM soit verrouillée.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"Code IIEM"</string>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"La mémoire de la montre est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"L\'espace de stockage de l\'appareil Android TV est plein. Supprimez des fichiers pour libérer de l\'espace."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}other{Autorités de certification installées}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}many{Autorités de certification installées}other{Autorités de certification installées}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Par un tiers inconnu"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Par l\'administrateur de votre profil professionnel"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport, d\'entrer plus d\'information sur le problème et d\'effectuer des saisies d\'écran. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Rapport complet"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilisez cette option pour qu\'il y ait le moins d\'interférences système possible lorsque votre appareil ne répond pas ou qu\'il est trop lent, ou lorsque vous avez besoin de toutes les sections du rapport de bogue. Aucune capture d\'écran supplémentaire ne peut être capturée, et vous ne pouvez entrer aucune autre information."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}one{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}other{Saisie d\'une capture d\'écran pour le rapport de bogue dans # secondes.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}one{Saisie d\'une capture d\'écran pour le rapport de bogue dans # seconde.}many{Saisie d\'une capture d\'écran pour le rapport de bogue dans # secondes.}other{Saisie d\'une capture d\'écran pour le rapport de bogue dans # secondes.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Capture d\'écran prise avec le rapport de bogue"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Échec de la prise de capture d\'écran avec le rapport de bogue"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Opération d\'empreinte digitale numérique annulée."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"L\'opération d\'empreinte digitale a été annulée par l\'utilisateur."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Trop de tentatives. Veuillez réessayer plus tard."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Trop de tentatives. Utilisez plutôt le verrouillage de l\'écran."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Réessayer."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Consultez un fournisseur de services de réparation."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossible de créer votre modèle facial. Réessayez."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Trop lumineux. Essayez un éclairage plus faible."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Essayez avec un éclairage plus fort"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Éloignez le téléphone"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Rapprochez le téléphone"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Tenez le téléphone plus haut"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Il y a plus d\'un mois"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dernier jour}one{# dernier jour}other{# derniers jours}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dernier jour}one{# dernier jour}many{# derniers jours}other{# derniers jours}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Le mois dernier"</string>
     <string name="older" msgid="1645159827884647400">"Précédent"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"le <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"dans <xliff:g id="COUNT">%d</xliff:g> h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"dans <xliff:g id="COUNT">%d</xliff:g> j"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"dans <xliff:g id="COUNT">%d</xliff:g> a"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}other{Il y a # minutes}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}other{Il y a # heures}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}other{Il y a # jours}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}other{Il y a # ans}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}other{# heures}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}other{# jours}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}other{# ans}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}many{Il y a # minutes}other{Il y a # minutes}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}many{Il y a # heures}other{Il y a # heures}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}many{Il y a # jours}other{Il y a # jours}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}many{Il y a # ans}other{Il y a # ans}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}many{# heures}other{# heures}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}many{# jours}other{# jours}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}many{# ans}other{# ans}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problème vidéo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Impossible de lire cette vidéo en continu sur cet appareil."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossible de lire la vidéo."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"non coché"</string>
     <string name="selected" msgid="6614607926197755875">"sélectionné"</string>
     <string name="not_selected" msgid="410652016565864475">"non sélectionné"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Une étoile sur {max}}one{# étoile sur {max}}other{# étoiles sur {max}}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Une étoile sur {max}}one{# étoile sur {max}}many{# d\'étoiles sur {max}}other{# étoiles sur {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"en cours"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Continuer avec %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
     <string name="no_matches" msgid="6472699895759164599">"Aucune partie"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}other{# sur {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}many{# sur {total}}other{# sur {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Terminé"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Effacement du stockage partagé en cours…"</string>
     <string name="share" msgid="4157615043345227321">"Partager"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Télévision"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Téléphone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Haut-parleurs de la station d\'accueil"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Oreillettes"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Système"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant une minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 m (jusqu\'à {formattedTime})}one{Pendant # m (jusqu\'à {formattedTime})}other{Pendant # m (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant une minute}one{Pendant # minute}other{Pendant # minutes}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 m}one{Pendant # m}other{Pendant # m}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}other{Pendant # heures}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}other{Pendant # h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant une minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}many{Pendant # minutes (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 m (jusqu\'à {formattedTime})}one{Pendant # m (jusqu\'à {formattedTime})}many{Pendant # m (jusqu\'à {formattedTime})}other{Pendant # m (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}many{Pendant # heures (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}many{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant une minute}one{Pendant # minute}many{Pendant # minutes}other{Pendant # minutes}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 m}one{Pendant # m}many{Pendant # m}other{Pendant # m}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}many{Pendant # heures}other{Pendant # heures}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}many{Pendant # h}other{Pendant # h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Enregistrer pour le remplissage automatique"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Le contenu ne peut pas être entré automatiquement"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Aucune suggestion de remplissage automatique"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Une suggestion de remplissage automatique}one{# suggestion de remplissage automatique}other{# suggestions de remplissage automatique}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Une suggestion de remplissage automatique}one{# suggestion de remplissage automatique}many{# suggestions de remplissage automatique}other{# suggestions de remplissage automatique}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"Enregistrer sous "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer <xliff:g id="TYPE">%1$s</xliff:g> sous "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> sous "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Présentation <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Le Bluetooth restera activé en mode Avion"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Chargement en cours…"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}other{{file_name} + # fichiers}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Liste des applications"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Cette application n\'a pas été autorisée à effectuer des enregistrements, mais elle pourrait capturer du contenu audio par l\'intermédiaire de cet appareil USB."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 95d06f4..a9dccbc 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -47,6 +47,7 @@
     <string name="enablePin" msgid="2543771964137091212">"Échec de l\'opération. Veuillez activer le verrouillage de la carte SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
       <item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne soit verrouillée.</item>
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne soit verrouillée.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"Code IMEI"</string>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"La mémoire de la montre est saturée. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"L\'espace de stockage de l\'appareil Android TV est saturé. Supprimez certains fichiers pour libérer de l\'espace."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}other{Autorités de certification installées}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorité de certification installée}one{Autorité de certification installée}many{Autorités de certification installées}other{Autorités de certification installées}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Par un tiers inconnu"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Par l\'administrateur de votre profil professionnel"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Par <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport, de saisir plus d\'informations sur le problème et d\'effectuer des captures d\'écran. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Rapport complet"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilisez cette option pour qu\'il y ait le moins d\'interférences système possible lorsque votre appareil ne répond pas ou qu\'il est trop lent, ou lorsque vous avez besoin de toutes les sections du rapport de bug. Aucune capture d\'écran supplémentaire ne peut être prise, et vous ne pouvez saisir aucune autre information."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capture d\'écran pour le rapport de bug dans # seconde.}one{Capture d\'écran pour le rapport de bug dans # seconde.}other{Capture d\'écran pour le rapport de bug dans # secondes.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capture d\'écran pour le rapport de bug dans # seconde.}one{Capture d\'écran pour le rapport de bug dans # seconde.}many{Capture d\'écran pour le rapport de bug dans # secondes.}other{Capture d\'écran pour le rapport de bug dans # secondes.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Capture d\'écran avec rapport de bug effectuée"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Échec de la capture d\'écran avec le rapport de bug"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Opération d\'empreinte digitale annulée."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Opération d\'authentification par empreinte digitale annulée par l\'utilisateur."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Trop de tentatives. Veuillez réessayer plus tard."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Trop de tentatives. Utilisez plutôt le verrouillage de l\'écran."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Veuillez réessayer."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Contactez un réparateur."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossible de créer l\'empreinte faciale. Réessayez."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Trop lumineux. Essayez de baisser la lumière."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Essayez un éclairage plus lumineux"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Éloignez le téléphone."</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Rapprochez le téléphone"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Déplacez le téléphone vers le haut"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Il y a plus d\'un mois"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Dernier jour (#)}one{Dernier jour (#)}other{# derniers jours}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Dernier jour (#)}one{Dernier jour (#)}many{# derniers jours}other{# derniers jours}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Le mois dernier"</string>
     <string name="older" msgid="1645159827884647400">"Préc."</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"le <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"dans <xliff:g id="COUNT">%d</xliff:g> h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"dans <xliff:g id="COUNT">%d</xliff:g> j"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"dans <xliff:g id="COUNT">%d</xliff:g> an"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}other{Il y a # minutes}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}other{Il y a # heures}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}other{Il y a # jours}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}other{Il y a # ans}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}other{# heures}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}other{# jours}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}other{# ans}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Il y a # minute}one{Il y a # minute}many{Il y a # minutes}other{Il y a # minutes}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Il y a # heure}one{Il y a # heure}many{Il y a # heures}other{Il y a # heures}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Il y a # jour}one{Il y a # jour}many{Il y a # jours}other{Il y a # jours}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Il y a # an}one{Il y a # an}many{Il y a # ans}other{Il y a # ans}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# heure}one{# heure}many{# heures}other{# heures}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# jour}one{# jour}many{# jours}other{# jours}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}one{# an}many{# ans}other{# ans}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problème vidéo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Impossible de lire cette vidéo en streaming sur cet appareil."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossible de lire la vidéo."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"désactivé"</string>
     <string name="selected" msgid="6614607926197755875">"sélectionné"</string>
     <string name="not_selected" msgid="410652016565864475">"non sélectionné"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 étoile sur {max}}one{# étoile sur {max}}other{# étoiles sur {max}}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 étoile sur {max}}one{# étoile sur {max}}many{# étoiles sur {max}}other{# étoiles sur {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"en cours"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Terminer l\'action avec %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
     <string name="no_matches" msgid="6472699895759164599">"Aucune correspondance"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Rechercher sur la page"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}other{# sur {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondance}one{# sur {total}}many{# sur {total}}other{# sur {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"OK"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Suppression de l\'espace de stockage partagé…"</string>
     <string name="share" msgid="4157615043345227321">"Partager"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Téléviseur"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Téléphone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Haut-parleurs de la station d\'accueil"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Écouteurs"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Système"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation des données, l\'Économiseur de données empêche certaines applis d\'envoyer ou de recevoir des données en arrière-plan. Les applis que vous utiliserez pourront toujours accéder aux données, mais le feront moins fréquemment. Par exemple, les images pourront ne pas s\'afficher tant que vous n\'aurez pas appuyé dessus."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'Économiseur de données ?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant 1 minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 min (jusqu\'à {formattedTime})}one{Pendant # min (jusqu\'à {formattedTime})}other{Pendant # min (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant 1 minute}one{Pendant # minute}other{Pendant # minutes}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 min}one{Pendant # min}other{Pendant # min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}other{Pendant # heures}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}other{Pendant # h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Pendant 1 minute (jusqu\'à {formattedTime})}one{Pendant # minute (jusqu\'à {formattedTime})}many{Pendant # minutes (jusqu\'à {formattedTime})}other{Pendant # minutes (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Pendant 1 min (jusqu\'à {formattedTime})}one{Pendant # min (jusqu\'à {formattedTime})}many{Pendant # min (jusqu\'à {formattedTime})}other{Pendant # min (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Pendant 1 heure (jusqu\'à {formattedTime})}one{Pendant # heure (jusqu\'à {formattedTime})}many{Pendant # heures (jusqu\'à {formattedTime})}other{Pendant # heures (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Pendant 1 h (jusqu\'à {formattedTime})}one{Pendant # h (jusqu\'à {formattedTime})}many{Pendant # h (jusqu\'à {formattedTime})}other{Pendant # h (jusqu\'à {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Pendant 1 minute}one{Pendant # minute}many{Pendant # minutes}other{Pendant # minutes}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Pendant 1 min}one{Pendant # min}many{Pendant # min}other{Pendant # min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Pendant 1 heure}one{Pendant # heure}many{Pendant # heures}other{Pendant # heures}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Pendant 1 h}one{Pendant # h}many{Pendant # h}other{Pendant # h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Enregistrer pour la saisie automatique"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Le contenu ne peut pas être saisi automatiquement"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Aucune suggestion de saisie automatique"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 suggestion de saisie automatique}one{# suggestion de saisie automatique}other{# suggestions de saisie automatique}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{1 suggestion de saisie automatique}one{# suggestion de saisie automatique}many{# suggestions de saisie automatique}other{# suggestions de saisie automatique}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"Enregistrer dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer la <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Présentation <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Le Bluetooth restera activé en mode Avion"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Chargement…"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}other{{file_name} + # fichiers}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # fichier}one{{file_name} + # fichier}many{{file_name} + # fichiers}other{{file_name} + # fichiers}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Aucune recommandation de personnes avec lesquelles effectuer un partage"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Liste des applications"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Cette application n\'a pas reçu l\'autorisation d\'enregistrer des contenus audio, mais peut le faire via ce périphérique USB."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2dd092d..ae29e50 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Cancelouse a operación da impresión dixital."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"O usuario cancelou a operación da impresión dixital."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Téntao de novo máis tarde."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiados intentos. Mellor usa o bloqueo de pantalla."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Téntao de novo."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Non se rexistraron impresións dixitais."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visita un provedor de reparacións."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Non se puido crear o modelo facial. Téntao de novo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Hai demasiada iluminación. Proba cunha máis suave."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Proba con máis luz"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Afasta o teléfono"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Achega o teléfono"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Sube o teléfono"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televisión"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Teléfono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Conectar altofalantes á base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auriculares"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index d170302..36812e8 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ફિંગરપ્રિન્ટ ઓપરેશન રદ કર્યું."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ફિંગરપ્રિન્ટ ચકાસવાની પ્રક્રિયા વપરાશકર્તાએ રદ કરી."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ઘણા બધા પ્રયત્નો. પછીથી ફરી પ્રયાસ કરો."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ઘણા બધા પ્રયાસો. વિકલ્પ તરીકે સ્ક્રીન લૉકનો ઉપયોગ કરો."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ફરી પ્રયાસ કરો."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"કોઈ ફિંગરપ્રિન્ટની નોંધણી કરવામાં આવી નથી."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"રિપેર કરવાની સેવા આપતા પ્રદાતાની મુલાકાત લો."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"તમારા ચહેરાનું મૉડલ ન બનાવી શકાય. ફરી પ્રયાસ કરો."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"અતિશય પ્રકાશિત. થોડો હળવો પ્રકાશ અજમાવી જુઓ."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"વધુ પ્રકાશિત લાઇટિંગ અજમાવો"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ફોનને વધુ દૂર લઈ જાઓ"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ફોનને વધુ નજીક લાવો"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ફોનને વધુ ઊંચે લઈ જાઓ"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ફોન"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"સ્પીકર્સ ડૉક કરો"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"હેડફોન"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"સિસ્ટમ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d970498..2a9a44a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -302,7 +302,7 @@
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"मैसेज (एसएमएस) भेजें और देखें"</string>
     <string name="permgrouplab_storage" msgid="17339216290379241">"फ़ाइलें"</string>
     <string name="permgroupdesc_storage" msgid="5378659041354582769">"अपने डिवाइस में मौजूद फ़ाइलों का ऐक्सेस दें"</string>
-    <string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"संगीत और ऑडियो के ऐक्सेस"</string>
+    <string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"संगीत और ऑडियो"</string>
     <string name="permgroupdesc_readMediaAural" msgid="7565467343667089595">"आपके डिवाइस पर संगीत और ऑडियो को ऐक्सेस करने की अनुमति"</string>
     <string name="permgrouplab_readMediaVisual" msgid="4724874717811908660">"फ़ोटो और वीडियो के ऐक्सेस"</string>
     <string name="permgroupdesc_readMediaVisual" msgid="4080463241903508688">"आपके डिवाइस पर फ़ोटो और वीडियो को ऐक्सेस करने की अनुमति"</string>
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"फ़िंगरप्रिंट ऑपरेशन रोक दिया गया."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"उपयोगकर्ता ने फिंगरप्रिंट की पुष्टि की कार्रवाई रद्द कर दी है."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"बहुत ज़्यादा प्रयास कर लिए गए हैं. बाद में फिर से प्रयास करें."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"इससे ज़्यादा बार कोशिश नहीं की जा सकती. इसके बजाय, स्क्रीन लॉक का इस्तेमाल करें."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से कोशिश करें."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"फ़िंगरप्रिंट सेंसर को रिपेयर करने की सेवा देने वाली कंपनी से संपर्क करें."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"चेहरे का माॅडल नहीं बन सका. फिर से कोशिश करें."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"बहुत रोशनी है. हल्की रोशनी आज़माएं."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"बेहतर रोशनी में कोशिश करें"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"फ़ोन को दूर ले जाएं"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"फ़ोन को नज़दीक लाएं"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"फ़ोन को थोड़ा और ऊपर ले जाएं"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टीवी"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फ़ोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"डॉक स्‍पीकर"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफ़ोन"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"यूएसबी"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"सिस्‍टम"</string>
@@ -1855,8 +1855,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, कुछ खास सुविधाओं, और कुछ खास तरह के इंटरनेट कनेक्शन इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
-    <string name="battery_saver_description" msgid="8518809702138617167">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, यह बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, कुछ खास सुविधाओं, और कुछ खास तरह के इंटरनेट कनेक्शन इस्तेमाल करने से डिवाइस को रोकता है या इन्हें बंद कर देता है."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, इस मोड में बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाएं कम या बंद हो जाती हैं. कुछ इंटरनेट कनेक्शन भी पूरी तरह काम नहीं करते."</string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, इस मोड में बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ सुविधाएं सीमित या बंद हो जाती हैं. कुछ इंटरनेट कनेक्शन भी पूरी तरह काम नहीं करते."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, जिस ऐप्लिकेशन का इस्तेमाल किया जा रहा है वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी, जब तक उन पर टैप नहीं किया जाएगा."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 1a0b1c6..0a2702a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -606,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Radnja otiska prsta otkazana je."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Radnju s otiskom prsta otkazao je korisnik."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Previše pokušaja. Umjesto toga upotrijebite zaključavanje zaslona."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Pokušajte ponovo."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registriran nijedan otisak prsta."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string>
@@ -636,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Posjetite davatelja usluga popravaka."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Izrada modela lica nije uspjela. Pokušajte ponovo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvijetlo je. Pokušajte sa slabijim svjetlom."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Pokušajte s jačim osvjetljenjem"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Udaljite telefon"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Približite telefon"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Pomaknite telefon prema gore"</string>
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televizor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvučnici postolja"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalice"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sustav"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 24dc9b6..01b6f90 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Ujjlenyomattal kapcsolatos művelet megszakítva"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Az ujjlenyomattal kapcsolatos műveletet a felhasználó megszakította."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Túl sok próbálkozás. Próbálja újra később."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Túl sok próbálkozás. Használja inkább a képernyőzárat."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Próbálkozzon újra."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nincsenek regisztrált ujjlenyomatok."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Keresse fel a szervizt."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nem lehet létrehozni az arcmodellt. Próbálja újra."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Túl világos. Próbálja kevésbé erős világítással."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Próbálja jobb megvilágítás mellett"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Tartsa távolabb a telefont"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Tartsa közelebb a telefont"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Emelje magasabbra a telefont"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokkolóegység hangszórója"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fejhallgató"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Rendszer"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index b9206c3..86560be 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Իսկորոշումը մատնահետքի միջոցով չեղարկվեց:"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Մատնահետքով նույնականացման գործողությունը չեղարկվել է օգտատիրոջ կողմից:"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Չափից շատ փորձ եք կատարել: Փորձեք նորից քիչ հետո:"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Չափազանց շատ փորձեր են արվել։ Օգտագործեք էկրանի կողպումը։"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Փորձեք նորից:"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Գրանցված մատնահետք չկա:"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Այցելեք սպասարկման կենտրոն։"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Չհաջողվեց ստեղծել ձեր դեմքի մոդելը։ Նորից փորձեք։"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Շատ լուսավոր է։ Փորձեք ավելի թեթև լուսավորություն։"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Ավելի պայծառ դարձրեք լուսավորությունը"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Փոքր-ինչ հեռու պահեք հեռախոսը"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Մոտեցրեք հեռախոսը"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Բարձրացրեք հեռախոսը"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Հեռուստացույց"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Հեռախոս"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Դոկ-կայանի բարձրախոսներ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ականջակալներ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Համակարգ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 30f98fd..b145e20 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operasi sidik jari dibatalkan."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operasi sidik jari dibatalkan oleh pengguna."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Terlalu banyak upaya. Coba lagi nanti."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Terlalu banyak upaya gagal. Gunakan kunci layar."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Coba lagi."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Kunjungi penyedia reparasi."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah Anda. Coba lagi."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Coba cahaya yang lebih lembut."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Coba pencahayaan yang lebih cerah"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Jauhkan ponsel"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Dekatkan ponsel"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Gerakkan ponsel ke atas"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Ponsel"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Pengeras suara dok"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Headphone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 20bf9bf..6f48de2 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Hætt við fingrafarsaðgerð."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Notandi hætti við að nota fingrafar."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Of margar tilraunir. Reyndu aftur síðar."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Of margar tilraunir. Notaðu skjálás í staðinn."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Reyndu aftur."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Engin fingraför hafa verið skráð."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Þú verður að fara á verkstæði."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ekki tekst að búa til andlitslíkan. Reyndu aftur."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Of bjart. Prófaðu mýkri lýsingu."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prófaðu sterkari lýsingu"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Færðu símann lengra frá"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Færðu símann nær"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Færðu símann hærra"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Sjónvarp"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Sími"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokkuhátalarar"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Heyrnartól"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Kerfi"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 330100c..fb7763a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -46,6 +46,7 @@
     <string name="needPuk2" msgid="7032612093451537186">"Digita il PUK2 per sbloccare la SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Operazione non riuscita; attiva blocco SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata.</item>
       <item quantity="one">Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata.</item>
     </plurals>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"La memoria dell\'orologio è piena. Elimina alcuni file per liberare spazio."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"Lo spazio di archiviazione del dispositivo Android TV è pieno. Elimina alcuni file per liberare spazio."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorità di certificazione installata}other{Autorità di certificazione installate}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autorità di certificazione installata}many{Autorità di certificazione installate}other{Autorità di certificazione installate}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Da una terza parte sconosciuta"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Dall\'amministratore del tuo profilo di lavoro"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Da <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilizza questa opzione nella maggior parte dei casi. Ti consente di monitorare l\'avanzamento della segnalazione, di inserire maggiori dettagli relativi al problema e di acquisire screenshot. Potrebbero essere omesse alcune sezioni meno utilizzate il cui inserimento nella segnalazione richiede molto tempo."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Report completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilizza questa opzione per ridurre al minimo l\'interferenza di sistema quando il dispositivo non risponde, è troppo lento oppure quando ti servono tutte le sezioni della segnalazione. Non puoi inserire altri dettagli o acquisire altri screenshot."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondo.}other{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondo.}many{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}other{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot con segnalazione di bug effettuato correttamente"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Impossibile acquisire screenshot con segnalazione di bug"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modalità silenziosa"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operazione associata all\'impronta annullata."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operazione di autenticazione dell\'impronta annullata dall\'utente."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Troppi tentativi. Riprova più tardi."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Troppi tentativi. Usa il blocco schermo."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Riprova."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nessuna impronta digitale registrata."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Contatta un fornitore di servizi di riparazione."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossibile creare il modello del volto. Riprova."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Troppa luce. Prova con una luce più soft."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prova con più luce"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Allontana il telefono"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Avvicina il telefono"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Sposta il telefono più in alto"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vuole attivare la funzione Esplora al tocco. Quando la funzione Esplora al tocco è attiva, puoi ascoltare o visualizzare le descrizioni di ciò che stai toccando oppure interagire con il telefono tramite gesti."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mese fa"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Oltre 1 mese fa"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Ultimo giorno}other{Ultimi # giorni}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{Ultimo giorno}many{Ultimi # giorni}other{Ultimi # giorni}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Ultimo mese"</string>
     <string name="older" msgid="1645159827884647400">"Precedente"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"tra <xliff:g id="COUNT">%d</xliff:g> h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"tra <xliff:g id="COUNT">%d</xliff:g> g"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"tra <xliff:g id="COUNT">%d</xliff:g> a"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto fa}other{# minuti fa}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# ora fa}other{# ore fa}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# giorno fa}other{# giorni fa}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# anno fa}other{# anni fa}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minuti}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# ora}other{# ore}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# giorno}other{# giorni}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# anno}other{# anni}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto fa}many{# minuti fa}other{# minuti fa}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# ora fa}many{# ore fa}other{# ore fa}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# giorno fa}many{# giorni fa}other{# giorni fa}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# anno fa}many{# anni fa}other{# anni fa}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minuti}other{# minuti}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# ora}many{# ore}other{# ore}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# giorno}many{# giorni}other{# giorni}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# anno}many{# anni}other{# anni}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problemi video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Questo video non è valido per lo streaming su questo dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Impossibile riprodurre il video."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"deselezionato"</string>
     <string name="selected" msgid="6614607926197755875">"selezionato"</string>
     <string name="not_selected" msgid="410652016565864475">"non selezionato"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Una stella su {max}}other{# stelle su {max}}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Una stella su {max}}many{# stelle su {max}}other{# stelle su {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"In corso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completa l\'azione con"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completamento azione con %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Salta"</string>
     <string name="no_matches" msgid="6472699895759164599">"Nessuna corrispondenza"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Trova nella pagina"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# corrispondenza}other{# di {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# corrispondenza}many{# di {total}}other{# di {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Fine"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Cancellazione archivio condiviso…"</string>
     <string name="share" msgid="4157615043345227321">"Condividi"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altoparlanti dock"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Cuffie audio"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzionalità Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Per esempio, è possibile che le immagini non vengano visualizzate finché non le tocchi."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Per un minuto (fino alle ore {formattedTime})}other{Per # minuti (fino alle ore {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Per 1 min (fino alle ore {formattedTime})}other{Per # min (fino alle ore {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Per 1 ora (fino alle ore {formattedTime})}other{Per # ore (fino alle ore {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Per 1 h (fino alle ore {formattedTime})}other{Per # h (fino alle ore {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Per un minuto}other{Per # minuti}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Per 1 min}other{Per # min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Per 1 ora}other{Per # ore}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Per 1 h}other{Per # h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Per un minuto (fino alle ore {formattedTime})}many{Per # minuti (fino alle ore {formattedTime})}other{Per # minuti (fino alle ore {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Per 1 min (fino alle ore {formattedTime})}many{Per # min (fino alle ore {formattedTime})}other{Per # min (fino alle ore {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Per 1 ora (fino alle ore {formattedTime})}many{Per # ore (fino alle ore {formattedTime})}other{Per # ore (fino alle ore {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Per 1 h (fino alle ore {formattedTime})}many{Per # h (fino alle ore {formattedTime})}other{Per # h (fino alle ore {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Per un minuto}many{Per # minuti}other{Per # minuti}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Per 1 min}many{Per # min}other{Per # min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Per 1 ora}many{Per # ore}other{Per # ore}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Per 1 h}many{Per # h}other{Per # h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Fino a: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salva per Compilazione automatica"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Impossibile compilare automaticamente i contenuti"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Nessun suggerimento di Compilazione automatica"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Un suggerimento di compilazione automatica}other{# suggerimenti di compilazione automatica}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Un suggerimento di compilazione automatica}many{# suggerimenti di compilazione automatica}other{# suggerimenti di compilazione automatica}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"Vuoi salvare su "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Vuoi salvare la <xliff:g id="TYPE">%1$s</xliff:g> su "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Vuoi salvare <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> su "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentazione <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Il Bluetooth rimane attivo durante l\'uso della modalità aereo"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Caricamento"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # file}other{{file_name} + # file}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # file}many{{file_name} + # file}other{{file_name} + # file}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Nessuna persona consigliata per la condivisione"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Elenco di app"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"A questa app non è stata concessa l\'autorizzazione di registrazione, ma l\'app potrebbe acquisire l\'audio tramite questo dispositivo USB."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 40a3a7d..7a460a3 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"פעולת טביעת האצבע בוטלה."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"פעולת טביעת האצבע בוטלה על ידי המשתמש."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"בוצעו יותר מדי ניסיונות. יש להשתמש בנעילת המסך במקום זאת."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"כדאי לנסות שוב."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"לא נסרקו טביעות אצבע."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר הזה אין חיישן טביעות אצבע."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"צריך ליצור קשר עם ספק תיקונים."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"לא ניתן ליצור את התבנית לזיהוי הפנים. יש לנסות שוב."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"בהירה מדי. צריך תאורה עדינה יותר."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"כדאי לנסות בתאורה חזקה יותר"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"צריך להרחיק את הטלפון"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"צריך לקרב את הטלפון"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"צריך להגביה את הטלפון"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"טלוויזיה"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"טלפון"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"רמקולים של מעגן"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"אוזניות"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"מערכת"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b1373c6..cf8521f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋の操作をキャンセルしました。"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"指紋の操作がユーザーによりキャンセルされました。"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"所定の回数以上間違えました。しばらくしてからもう一度お試しください。"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"試行回数が上限を超えました。代わりに画面ロックを使用してください。"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"もう一度お試しください。"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string>
@@ -635,7 +634,7 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"修理業者に調整を依頼してください。"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"顔モデルを作成できません。もう一度お試しください。"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"明るすぎます。もっと暗い場所でお試しください。"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"もっと明るい場所でお試しください"</string>
+    <string name="face_acquired_too_dark" msgid="8539853432479385326">"十分な光がありません"</string>
     <string name="face_acquired_too_close" msgid="4453646176196302462">"スマートフォンをもっと離してください"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"スマートフォンをもっと近づけてください"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"スマートフォンをもっと上げてください"</string>
@@ -1611,7 +1610,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"テレビ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"モバイル デバイス"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ホルダーのスピーカー"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ヘッドホン"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"システム"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 090fc1f..ae14cc9 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"თითის ანაბეჭდის აღების ოპერაცია გაუქმდა."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"თითის ანაბეჭდის ოპერაცია გააუქმა მომხმარებელმა."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ძალიან ბევრი მცდელობა იყო. სცადეთ მოგვიანებით."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"მეტისმეტად ბევრი მცდელობა იყო. სანაცვლოდ გამოიყენეთ ეკრანის დაბლოკვა."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ხელახლა სცადეთ"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"თითის ანაბეჭდები რეგისტრირებული არ არის."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ეწვიეთ შეკეთების სერვისის პროვაიდერს."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"თქვენი სახის მოდელი ვერ იქმნება. ცადეთ ხელახლა."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"მეტისმეტად ნათელია. ცადეთ უფრო სუსტი განათება."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ცადეთ უფრო ძლიერი განათება"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"გაწიეთ ტელეფონი უფრო შორს"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"მიიტანეთ ტელეფონი უფრო ახლოს"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"აწიეთ ტელეფონი ზემოთ"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ტელევიზია"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ტელეფონი"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"სპიკერების მიმაგრება"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ყურსასმენები"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"სისტემა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index afd0bf8..54edba3 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Жөндеу қызметіне барыңыз."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Бет үлгісі жасалмады. Қайталап көріңіз."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Тым ашық. Күңгірттеу жарық керек."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Жарық деңгейін арттырыңыз."</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Телефонды алшақ ұстаңыз."</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Телефонды жақынырақ ұстаңыз."</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Телефонды жоғарырақ ұстаңыз."</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ТД"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Үндеткіштерді қондыру"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Құлақаспаптар"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Жүйе"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index a878eb3..0d3d07d 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"បានបោះបង់ប្រតិបត្តិការស្នាមម្រាមដៃ។"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ប្រតិបត្តិការ​ស្នាម​ម្រាម​ដៃ​ត្រូវ​បាន​បោះ​បង់​ដោយ​អ្នក​ប្រើប្រាស់។"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ព្យាយាម​ច្រើនដងពេក។ សូមប្រើការចាក់សោ​អេក្រង់ជំនួសវិញ។"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ព្យាយាមម្ដងទៀត។"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"មិន​មាន​ការ​ចុះឈ្មោះស្នាម​ម្រាមដៃទេ។"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះ​មិនមាន​ឧបករណ៍ចាប់​ស្នាមម្រាមដៃទេ។"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ទាក់ទងក្រុមហ៊ុន​ផ្ដល់ការជួសជុល។"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"មិនអាចបង្កើតគំរូមុខរបស់អ្នកបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ភ្លឺពេក។ សូមសាកល្បង​ប្រើ​ពន្លឺស្រាលជាងនេះ។"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"សាកល្បងប្រើ​ពន្លឺភ្លឺជាងនេះ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ដាក់​ទូរសព្ទឱ្យឆ្ងាយ​ជាងមុន"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ដាក់​ទូរសព្ទ​ឱ្យជិត​ជាងមុន"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ដាក់​ទូរសព្ទ​ឱ្យខ្ពស់​ជាងមុន"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ទូរទស្សន៍"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ទូរសព្ទ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ភ្ជាប់​អូប៉ាល័រ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"កាស"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ប្រព័ន្ធ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 1bcc705..9925a26 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ಬಳಕೆದಾರರು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಕಾರ್ಯಾಚರಣೆಯನ್ನು ರದ್ದುಪಡಿಸಿದ್ದಾರೆ."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ಹಲವಾರು ಪ್ರಯತ್ನಗಳು. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಬದಲಾಗಿ ಪರದೆಲಾಕ್ ಬಳಸಿ."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ಯಾವುದೇ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್‌ ಅನ್ನು ನೋಂದಣಿ ಮಾಡಿಲ್ಲ."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌‌ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ರಿಪೇರಿ ಮಾಡುವವರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"ಫೇಸ್ ಮಾಡೆಲ್ ರಚಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ ಮಂದ ಪ್ರಕಾಶಮಾನವಿರುವ ಲೈಟ್ ಬಳಸಿ"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ಪ್ರಕಾಶಮಾನವಾದ ಲೈಟಿಂಗ್ ಬಳಸಿ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ಫೋನ್ ಅನ್ನು ದೂರಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ಫೋನ್ ಅನ್ನು ಸಮೀಪಕ್ಕೆ ತನ್ನಿ"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ಫೋನ್ ಅನ್ನು ಮೇಲಕ್ಕೆ ಎತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ಟಿವಿ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ಫೋನ್"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ಡಾಕ್ ಸ್ಪೀಕರ್‍‌ಗಳು"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ಹೆಡ್‌ಫೋನ್‌ಗಳು"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ಸಿಸ್ಟಂ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a08d2aa..40c545f 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"지문 인식 작업이 취소되었습니다."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"사용자가 지문 인식 작업을 취소했습니다."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"시도 횟수가 너무 많습니다. 화면 잠금을 대신 사용하세요."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"다시 시도해 보세요."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"등록된 지문이 없습니다."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"수리업체에 방문하세요."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"얼굴 모델을 만들 수 없습니다. 다시 시도해 주세요."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"너무 밝습니다. 조명 밝기를 조금 낮춰보세요."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"조명을 밝게 해 보세요."</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"휴대전화를 얼굴에서 더 멀리 떨어뜨려 주세요."</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"휴대전화를 얼굴에 더 가까이 가져와 주세요."</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"휴대전화를 위로 이동하세요"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"휴대전화"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"도크 스피커"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"헤드폰"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"시스템"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 7572c4b..f27b0d6 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Манжа изи иш-аракети жокко чыгарылды."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Манжа изи операциясын колдонуучу жокко чыгарды."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Аракеттер өтө көп болду. Бир аздан кийин кайталап көрүңүз."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Өтө көп жолу аракет кылдыңыз. Экранды кулпулоо функциясын колдонуңуз."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Кайра бир аракеттениңиз."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бир да манжа изи катталган эмес."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Тейлөө кызматына кайрылыңыз."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Жүзүңүздүн үлгүсү түзүлгөн жок. Кайталаңыз."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Өтө жарык. Жарыктыкты азайтып көрүңүз."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Жарыгыраак жерге туруңуз"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Телефонду алыстатыңыз"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Телефонду жакындатыңыз"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Телефонду жогору жылдырыңыз"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Сыналгы"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Аудио док бекет"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Кулакчын"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Тутум"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 8bfe9e2..7c9f815 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ຍົກ​ເລີກ​ການ​ດຳ​ເນີນ​ການ​ລາຍ​ນີ້ວ​ມື​ແລ້ວ."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ຜູ້ໃຊ້ໄດ້ຍົກເລີກຄຳສັ່ງລາຍນິ້ວມືແລ້ວ."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ມີ​ຄວາມ​ພະ​ຍາ​ຍາມ​ຫຼາຍ​ຄັ້ງ​ເກີນ​ໄປ. ລອງ​ໃໝ່​ພາຍ​ຫຼັງ."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ. ກະລຸນາໃຊ້ການລອກໜ້າຈໍແທນ."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ລອງໃໝ່ອີກຄັ້ງ."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ບໍ່ມີການລົງທະບຽນລາຍນິ້ວມື."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ກະລຸນາໄປຫາຜູ້ໃຫ້ບໍລິການສ້ອມແປງ."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"ບໍ່ສາມາດສ້າງຮູບແບບໃບໜ້າຂອງທ່ານໄດ້. ກະລຸນາລອງໃໝ່."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ແຈ້ງເກີນໄປ. ລອງຄ່ອຍແສງໄຟລົງ."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ກະລຸນາລອງໃຊ້ສະພາບແສງທີ່ແຈ້ງຂຶ້ນ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ເລື່ອນໂທລະສັບອອກໄປໄກຂຶ້ນ"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ເລື່ອນໂທລະສັບເຂົ້າໄປໃກ້ຂຶ້ນ"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ຍົກໂທລະສັບໃຫ້ສູງຂຶ້ນ"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ໂທລະພາບ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ໂທລະສັບ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ບ່ອນຕັ້ງລຳໂພງ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ຫູຟັງ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ລະບົບ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index afa77e6..2954f9c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Piršto antspaudo operacija atšaukta."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Piršto antspaudo operaciją atšaukė naudotojas."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Per daug bandymų. Naudokite ekrano užraktą."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Bandykite dar kartą."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neužregistruota jokių kontrolinių kodų."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Apsilankykite pas taisymo paslaugos teikėją."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nepavyko sukurti veido modelio. Band. dar kartą."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Per šviesu. Išbandykite mažesnį apšvietimą."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Išbandykite šviesesnį apšvietimą"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Laikykite telefoną toliau"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Laikykite telefoną arčiau"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Laikykite telefoną aukščiau"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefonas"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Doko garsiakalbiai"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ausinės"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d44c435..853a490 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -606,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Nospieduma darbība neizdevās."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Lietotājs atcēla pirksta nospieduma darbību."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Pārāk daudz mēģinājumu. Izmantojiet ekrāna bloķēšanu."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Mēģiniet vēlreiz."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string>
@@ -636,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Sazinieties ar remonta pakalpojumu sniedzēju."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nevar izveidot sejas modeli. Mēģiniet vēlreiz."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Pārāk spilgts. Izmēģiniet maigāku apgaismojumu."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Izmēģiniet spožāku apgaismojumu"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Pārvietojiet tālruni tālāk."</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Pārvietojiet tālruni tuvāk."</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Paceliet tālruni augstāk."</string>
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Tālrunis"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Doka skaļruņi"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Austiņas"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistēma"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index e74bc07..9ce43d1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Операцијата со отпечаток се откажа."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Корисникот ја откажа потврдата со отпечаток."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Премногу обиди. Обидете се повторно подоцна."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Премногу обиди. Користете заклучување екран."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Обидете се повторно."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Не се запишани отпечатоци."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Однесете го на поправка."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Не може да создаде модел на лик. Обидете се пак."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Премногу светла. Пробајте со послабо осветлување."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Пробајте со посилно осветлување"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Оддалечете го телефонот"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Доближете го телефонот"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Кренете го телефонот погоре"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевизор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Приклучи звучници"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Слушалки"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Систем"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 70b706a..c71047d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ഫിംഗർപ്രിന്റ് പ്രവർത്തനം റദ്ദാക്കി."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ഉപയോക്താവ് റദ്ദാക്കിയ ഫിംഗർപ്രിന്‍റ് പ്രവർത്തനം."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"നിരവധി ശ്രമങ്ങൾ. പകരം സ്‌ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"വീണ്ടും ശ്രമിക്കൂ."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"വിരലടയാളങ്ങൾ എൻറോൾ ചെയ്തിട്ടില്ല."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"റിപ്പയർ കേന്ദ്രം സന്ദർശിക്കുക."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"മുഖ മോഡൽ സൃഷ്ടിക്കാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"വളരെയധികം തെളിച്ചം. സൗമ്യതയേറിയ പ്രകാശം ശ്രമിക്കൂ."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"കൂടുതൽ വെളിച്ചമുള്ളയിടത്ത് പരീക്ഷിച്ച് നോക്കൂ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ഫോൺ കൂടുതൽ ദൂരേയ്ക്ക് നീക്കുക"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ഫോൺ അടുത്തേക്ക് നീക്കുക"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ഫോൺ മുകളിലേക്ക് ഉയർത്തുക"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ടിവി"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ഫോണ്‍"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ഡോക്ക് സ്‌പീക്കറുകൾ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ഹെഡ്‌ഫോണുകൾ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"സിസ്റ്റം"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4e50f56..417500d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Хурууны хээний бүртгэл амжилтгүй боллоо."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Хэрэглэгч хурууны хээний баталгаажуулалтыг цуцалсан байна."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Хэтэрхий олон оролдлоо.  Түр хүлээгээд дахин оролдоно уу."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Хэт олон удаа оролдлоо. Оронд нь дэлгэцийн түгжээ ашиглана уу."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Дахин оролдно уу."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бүртгүүлсэн хурууны хээ алга."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Засварын үйлчилгээ үзүүлэгчид зочилно уу."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Нүүрний загвар үүсгэж чадсангүй. Дахин оролдоно уу."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Хэт цайвар байна. Гэрэл багатай газар оролдоно уу."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Гэрэлтэй орчинд туршина уу"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Утсаа холдуулна уу"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Утсаа ойртуулна уу"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Утсаа дээшлүүлнэ үү"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tелевиз"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Утас"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Чанга яригчийг суулгах"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Чихэвч"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Систем"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 371f776..f91a18f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"फिंगरप्रिंट ऑपरेशन रद्द झाले."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"वापरकर्त्याने फिंगरप्रिंट ऑपरेशन रद्द केले."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"खूप प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"खूप जास्त प्रयत्न. त्याऐवजी स्क्रीन लॉक वापरा."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"पुन्हा प्रयत्न करा."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोणत्याही फिंगरप्रिंटची नोंद झाली नाही"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"दुरुस्तीच्या सेवा पुरवठादाराला भेट द्या."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"फेस मॉडेल तयार करू शकत नाही. पुन्हा प्रयत्न करा."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"खूप प्रखर. आणखी सौम्य प्रकाश वापरून पहा."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"आणखी प्रखर प्रकाश वापरून पहा"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"फोन आणखी दूर हलवा"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"फोन आणखी जवळ हलवा"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"फोन आणखी वर हलवा"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टीव्ही"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"स्पीकर डॉक करा"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफोन"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"सिस्टम"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2179308..9b76a16 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Pengendalian cap jari dibatalkan."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Pengendalian cap jari dibatalkan oleh pengguna."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Terlalu banyak percubaan. Gunakan kunci skrin."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Cuba lagi."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tiada cap jari didaftarkan."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Lawati penyedia pembaikan."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah anda. Cuba lagi."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Terlalu terang. Cuba pencahayaan yang lebih lembut."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Cuba pencahayaan yang lebih cerah"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Jauhkan telefon"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Dekatkan telefon"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Tinggikan lagi telefon"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Pembesar suara dok"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fon kepala"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index ebaa967..87916c4 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"လက်ဗွေယူခြင်း ပယ်ဖျက်လိုက်သည်။"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"လက်ဗွေဖြင့် အထောက်အထားစိစစ်ခြင်းကို အသုံးပြုသူက ပယ်ဖျက်ထားသည်။"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ကြိုးစာမှု အကြိမ်များနေ၏။ နောက်မှ ထပ်မံကြိုးစားပါ။"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်းသည်။ ဖန်သားပြင်လော့ခ်ချခြင်းကို အစားထိုးသုံးပါ။"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ပြန်ကြိုးစားပါ"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ပြုပြင်ရေး ဝန်ဆောင်မှုပေးသူထံသို့ သွားပါ။"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"သင့်မျက်နှာနမူနာ ပြုလုပ်၍မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"အလွန် လင်းသည်။ အလင်းလျှော့ကြည့်ပါ။"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ပိုလင်းအောင် လုပ်ကြည့်ပါ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ဖုန်းကို အဝေးသို့ခွာပါ"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ဖုန်းကို အနားသို့ပိုတိုးပါ"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ဖုန်းကို ပိုမြှင့်လိုက်ပါ"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ဖုန်း"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"အထိုင်ရှိသော စပီကာများ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"နားကြပ်"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"စနစ်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 120c08a..e101548 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingeravtrykk-operasjonen ble avbrutt."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingeravtrykk-operasjonen ble avbrutt av brukeren."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"For mange forsøk. Prøv på nytt senere."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"For mange forsøk. Bruk skjermlås i stedet."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Prøv på nytt."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ingen fingeravtrykk er registrert."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Gå til en reparasjonsleverandør."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan ikke lage ansiktsmodell. Prøv på nytt."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"For lyst. Prøv svakere belysning."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Prøv sterkere belysning"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Flytt telefonen lengre unna"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Flytt telefonen nærmere"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Flytt telefonen høyere"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Google TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dokkhøyttalere"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hodetelefoner"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index d8f8077..b2bf381 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"फिंगरप्रिन्ट सञ्चालन रद्द गरियो।"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"प्रयोगकर्ताले फिंगरप्रिन्टसम्बन्धी कारबाही रद्द गर्नुभयो।"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"धेरै प्रयासहरू। केहि समय पछि पुन: प्रयास गर्नुहोला"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"निकै धेरै पटक प्रयास गरिसकिएको छ। बरु स्क्रिन लक प्रयोग गर्नुहोस्।"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"पुन: प्रयास गर्नुहोला।"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कुनै पनि फिंगरप्रिन्ट दर्ता गरिएको छैन।"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो डिभाइसमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"फिंगरप्रिन्ट सेन्सर मर्मत गर्ने सेवा प्रदायक कम्पनीमा सम्पर्क गर्नुहोस्।"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"तपाईंको फेस मोडेल सिर्जना गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ज्यादै चम्किलो। अझ मधुरो प्रकाश प्रयोग गरी हेर्नु…"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"अझ उज्यालो ठाउँमा गएर फोटो खिची हेर्नुहोस्"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"फोन अझै पर सार्नुहोस्"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"फोन अझै नजिक सार्नुहोस्"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"फोन अझ माथि उठाउनुहोस्"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टिभी"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"फोन"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"डक स्पिकरहरू"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफोनहरू"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"प्रणाली"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3ff13f6..9811e27 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Vingerafdrukbewerking geannuleerd."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Vingerafdrukverificatie geannuleerd door gebruiker."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Te veel pogingen. Probeer het later opnieuw."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Te veel pogingen. Gebruik in plaats daarvan de schermvergrendeling."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probeer het opnieuw."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukken geregistreerd."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Ga naar een reparateur."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Kan gezichtsmodel niet maken. Probeer het opnieuw."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Overbelicht. Probeer een minder felle belichting."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Probeer fellere verlichting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Houd de telefoon verder weg"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Houd de telefoon dichterbij"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Houd de telefoon hoger"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tv"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefoon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dockluidsprekers"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hoofdtelefoon"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Systeem"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 29391d6..d3cbaec 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ଟିପଚିହ୍ନ କାର୍ଯ୍ୟ ବାତିଲ୍ କରାଗଲା।"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ଉପଯୋଗକର୍ତ୍ତା ଟିପଚିହ୍ନ କାର୍ଯ୍ୟ ବାତିଲ୍ କରିଛନ୍ତି।"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ବହୁତ ପ୍ରୟାସ କରାଗଲା। ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ଅନେକଗୁଡ଼ିଏ ପ୍ରଚେଷ୍ଟା। ଏହା ପରିବର୍ତ୍ତେ ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"କୌଣସି ଆଙ୍ଗୁଠି ଚିହ୍ନ ପଞ୍ଜୀକୃତ ହୋଇନାହିଁ।"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍‌ରେ ଟିପଚିହ୍ନ ସେନ୍‍ସର୍ ନାହିଁ।"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ଏକ ମରାମତି କେନ୍ଦ୍ରକୁ ଭିଜିଟ୍ କରନ୍ତୁ।"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"ଫେସର ମଡେଲ ତିଆରି କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କର।"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ଅତ୍ୟଧିକ ଉଜ୍ଵଳ। କମ୍ ଉଜ୍ବଳକରଣରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ଉଜ୍ଜ୍ୱଳ ଲାଇଟ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ଫୋନକୁ ଟିକେ ଦୂରକୁ ନିଅନ୍ତୁ"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ଫୋନକୁ ପାଖକୁ ଆଣନ୍ତୁ"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ଫୋନକୁ ଉପରକୁ ମୁଭ କରନ୍ତୁ"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ଫୋନ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ଡକ୍‌ ସ୍ପିକର୍‌"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ହେଡଫୋନ୍‍"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ସିଷ୍ଟମ"</string>
@@ -2044,7 +2044,7 @@
     <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"ଶର୍ଟକଟ୍‍ ରିଷ୍ଟୋର୍‍ କରିହେଲା ନାହିଁ, କାରଣ ଏହି ଆପ୍‍ର ସ୍ୱାକ୍ଷର ମେଳ ହେଉନାହିଁ"</string>
     <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"ଶର୍ଟକଟ୍‍ ରିଷ୍ଟୋର୍‍ କରିହେଲା ନାହିଁ"</string>
     <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"ଶର୍ଟକଟ୍‍ ଅକ୍ଷମ କରାଯାଇଛି"</string>
-    <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ଅନଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
+    <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
     <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"କୌଣସିମତେ ଖୋଲନ୍ତୁ"</string>
     <string name="harmful_app_warning_title" msgid="8794823880881113856">"ହାନିକାରକ ଆପ୍‌ ଚିହ୍ନଟ ହୋଇଛି"</string>
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 0433cf4..2ffeef4 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਓਪਰੇਸ਼ਨ ਰੱਦ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਓਪਰੇਸ਼ਨ ਵਰਤੋਂਕਾਰ ਵੱਲੋਂ ਰੱਦ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ. ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸਦੀ ਬਜਾਏ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ।"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ਕੋਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਰਜ ਨਹੀਂ ਕੀਤੇ ਗਏ।"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ਮੁਰੰਮਤ ਪ੍ਰਦਾਨਕ \'ਤੇ ਜਾਓ।"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"ਤੁਹਾਡੇ ਚਿਹਰੇ ਦਾ ਮਾਡਲ ਨਹੀਂ ਬਣਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ। ਹਲਕੀ ਚਮਕ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ਤੇਜ਼ ਰੋਸ਼ਨੀ ਕਰ ਕੇ ਦੇਖੋ"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ਫ਼ੋਨ ਨੂੰ ਦੂਰ ਲਿਜਾਓ"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ਫ਼ੋਨ ਨੇੜੇ ਲਿਜਾਓ"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ਫ਼ੋਨ ਨੂੰ ਥੋੜ੍ਹਾ ਉੱਤੇ ਲਿਜਾਓ"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ਫ਼ੋਨ ਕਰੋ"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ਡੌਕ ਸਪੀਕਰਸ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ਹੈੱਡਫ਼ੋਨ"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ਸਿਸਟਮ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ed1e709..88b54b0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Odczyt odcisku palca został anulowany."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Odczyt odcisku palca został anulowany przez użytkownika."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Zbyt wiele prób. Spróbuj ponownie później."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Zbyt wiele prób. Użyj blokady ekranu."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Spróbuj ponownie."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nie zarejestrowano odcisków palców."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Odwiedź serwis."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nie można utworzyć modelu twarzy. Spróbuj ponownie."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Zbyt jasno. Spróbuj przy słabszym świetle."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Spróbuj w jaśniejszym świetle"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Odsuń telefon"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Przybliż telefon"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Przesuń telefon wyżej"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Telewizor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Głośniki stacji dokującej"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Słuchawki"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ce63b94..7d5721a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -47,6 +47,7 @@
     <string name="enablePin" msgid="2543771964137091212">"Falha. Ative o bloqueio do chip/R-UIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
       <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Exclua alguns arquivos para liberar espaço."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}other{Autoridades certificadoras instaladas}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}many{Autoridades certificadoras instaladas}other{Autoridades certificadoras instaladas}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por terceiros desconhecidos"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo administrador do seu perfil de trabalho"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Use este recurso na maioria das circunstâncias. Ele permite que você acompanhe o progresso do relatório, informe mais detalhes sobre o problema e faça capturas de tela. É possível que ele omita algumas seções menos utilizadas que levam muito tempo na emissão dos relatórios."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Use esta opção para ter o mínimo de interferência do sistema quando seu dispositivo não estiver respondendo ou estiver muito lento, ou quando você precisar de todas as seções de relatórios. Ela não permite que você informe mais detalhes ou faça capturas de tela adicionais."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}many{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de tela com o relatório do bug concluída"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao capturar a tela com o relatório do bug"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operação de impressão digital cancelada."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operação de impressão digital cancelada pelo usuário."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Excesso de tentativas. Tente novamente mais tarde."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Excesso de tentativas. Use o bloqueio de tela."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Entre em contato com uma assistência técnica."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Falha ao criar o modelo de rosto. Tente de novo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Muito iluminado. Diminua a iluminação."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Use uma iluminação mais intensa"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste o smartphone"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o smartphone do seu rosto"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o smartphone para cima"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar o Explorar por toque. Com ele, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone por gestos."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mês atrás"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Antes de 1 mês atrás"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}other{Nos últimos # dias}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}many{Nos últimos # dias}other{Nos últimos # dias}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Mês passado"</string>
     <string name="older" msgid="1645159827884647400">"Mais antigos"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"em <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g>h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> dias"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g>a"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}other{# minutos atrás}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}other{# horas atrás}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}other{# dias atrás}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}other{# anos atrás}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}other{# minutos}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}other{# horas}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}other{# dias}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}other{# anos}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}many{# minutos atrás}other{# minutos atrás}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}many{# horas atrás}other{# horas atrás}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}many{# dias atrás}other{# dias atrás}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}many{# anos atrás}other{# anos atrás}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}many{# minutos}other{# minutos}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}many{# horas}other{# horas}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}many{# dias}other{# dias}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}many{# anos}other{# anos}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Não é possível reproduzir este vídeo."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
     <string name="selected" msgid="6614607926197755875">"selecionado"</string>
     <string name="not_selected" msgid="410652016565864475">"não selecionado"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 de {max} estrelas}one{# de {max} estrelas}other{# de {max} estrelas}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 de {max} estrelas}one{# de {max} estrelas}many{# de {max} estrelas}other{# de {max} estrelas}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"em andamento"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
     <string name="no_matches" msgid="6472699895759164599">"Não encontrado"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}other{# de {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}many{# de {total}}other{# de {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Limpando armazenamento compartilhado…"</string>
     <string name="share" msgid="4157615043345227321">"Compartilhar"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Alto-falantes na base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fones de ouvido"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você está usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não apareçam até você tocar nelas."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}other{Por # minutos}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}other{Por #min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}other{Por # horas}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}other{Por #h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}many{Por # minutos (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}many{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}many{Por # horas (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}many{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}many{Por # minutos}other{Por # minutos}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}many{Por #min}other{Por #min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}many{Por # horas}other{Por # horas}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}many{Por #h}other{Por #h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salvar no Preenchimento automático"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher os conteúdos automaticamente"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões de preenchimento automático"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}many{# sugestões de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"Salvar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Salvar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Salvar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá ativado no modo avião"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Carregando"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}other{{file_name} + # arquivos}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}many{{file_name} + # arquivos}other{{file_name} + # arquivos}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não há sugestões de pessoas para compartilhar"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 55cb68b..1fe0db7a 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -46,6 +46,7 @@
     <string name="needPuk2" msgid="7032612093451537186">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Ação sem êxito. Ative o bloqueio do SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item>
       <item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item>
     </plurals>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"O armazenamento de visualizações está cheio. Elimine alguns ficheiros para libertar espaço."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Elimine alguns ficheiros para libertar espaço."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade de certificação instalada}other{Autoridades de certificação instaladas}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade de certificação instalada}many{Autoridades de certificação instaladas}other{Autoridades de certificação instaladas}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por um terceiro desconhecido"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo gestor do seu perfil de trabalho"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Utilize esta opção na maioria das circunstâncias. Permite monitorizar o progresso do relatório, introduzir mais detalhes acerca do problema e tirar capturas de ecrã. Pode omitir algumas secções menos utilizadas que demoram muito tempo a comunicar."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilize esta opção para uma interferência mínima do sistema quando o dispositivo não responder ou estiver demasiado lento, ou quando precisar de todas as secções de relatório. Não permite introduzir mais detalhes ou tirar capturas de ecrã adicionais."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{A fazer uma captura de ecrã do relatório de erro dentro de # segundo.}other{A fazer uma captura de ecrã do relatório de erro dentro de # segundos.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{A fazer uma captura de ecrã do relatório de erro dentro de # segundo.}many{A fazer uma captura de ecrã do relatório de erro dentro de # segundos.}other{A fazer uma captura de ecrã do relatório de erro dentro de # segundos.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de ecrã tirada com o relatório de erro."</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao fazer captura de ecrã com o relatório de erro."</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operação de impressão digital cancelada."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operação de impressão digital cancelada pelo utilizador."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiadas tentativas. Tente novamente mais tarde."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Demasiadas tentativas. Em alternativa, use o bloqueio de ecrã."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registada."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Visite um fornecedor de serviços de reparação."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Impossível criar modelo de rosto. Tente novamente."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Demasiado clara. Experimente uma luz mais suave."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Experimente um local com mais luz"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste ainda mais o telemóvel"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o telemóvel do rosto"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o telemóvel mais para cima"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> pretende ativar a funcionalidade Explorar Através do Toque. Quando a funcionalidade Explorar Através do Toque estiver ativada, pode ouvir ou visualizar descrições sobre o que está por baixo do seu dedo ou executar gestos para interagir com o telemóvel."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"Há 1 mês"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Há mais de 1 mês"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dia anterior}other{# dias anteriores}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{# dia anterior}many{# dias anteriores}other{# dias anteriores}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Último mês"</string>
     <string name="older" msgid="1645159827884647400">"Mais antiga"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"a <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g> h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> d"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g> a"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Há # minuto}other{Há # minutos}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Há # hora}other{Há # horas}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Há # dia}other{Há # dias}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Há # ano}other{Há # anos}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}other{# minutos}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}other{# horas}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}other{# dias}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}other{# anos}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Há # minuto}many{Há # minutos}other{Há # minutos}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Há # hora}many{Há # horas}other{Há # horas}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Há # dia}many{Há # dias}other{Há # dias}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{Há # ano}many{Há # anos}other{Há # anos}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}many{# horas}other{# horas}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}many{# dias}other{# dias}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}many{# anos}other{# anos}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste aparelho."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Não é possível reproduzir este vídeo."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"não selecionado"</string>
     <string name="selected" msgid="6614607926197755875">"selecionado"</string>
     <string name="not_selected" msgid="410652016565864475">"não selecionado"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Uma estrela de {max}}other{# estrelas de {max}}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Uma estrela de {max}}many{# estrelas de {max}}other{# estrelas de {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"em curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Concluir ação utilizando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir ação utilizando %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Ignorar"</string>
     <string name="no_matches" msgid="6472699895759164599">"Sem correspondências"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}other{# de {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}many{# de {total}}other{# de {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"A apagar o armazenamento partilhado…"</string>
     <string name="share" msgid="4157615043345227321">"Partilhar"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telemóvel"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altif. estação ancoragem"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Auscultadores"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas apps enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Poupança de dados?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante um minuto (até à[s] {formattedTime})}other{Durante # minutos (até à[s] {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (até à[s] {formattedTime})}other{Durante # min (até à[s] {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (até à[s] {formattedTime})}other{Durante # horas (até à[s] {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (até à[s] {formattedTime})}other{Durante # h (até à[s] {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante um minuto}other{Durante # minutos}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}other{Durante # min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}other{Durante # horas}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}other{Durante # h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante um minuto (até à[s] {formattedTime})}many{Durante # minutos (até à[s] {formattedTime})}other{Durante # minutos (até à[s] {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Durante 1 min (até à[s] {formattedTime})}many{Durante # min (até à[s] {formattedTime})}other{Durante # min (até à[s] {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Durante 1 hora (até à[s] {formattedTime})}many{Durante # horas (até à[s] {formattedTime})}other{Durante # horas (até à[s] {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Durante 1 h (até à[s] {formattedTime})}many{Durante # h (até à[s] {formattedTime})}other{Durante # h (até à[s] {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Durante um minuto}many{Durante # minutos}other{Durante # minutos}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Durante 1 min}many{Durante # min}other{Durante # min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Durante 1 hora}many{Durante # horas}other{Durante # horas}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Durante 1 h}many{Durante # h}other{Durante # h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Guardar para o Preenchimento automático"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher automaticamente o conteúdo"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões do preenchimento automático"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão do preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão do preenchimento automático}many{# sugestões de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"Pretende guardar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Pretende guardar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Pretende guardar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth continuará ativado durante o modo de avião."</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"A carregar…"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ficheiro}other{{file_name} + # ficheiros}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ficheiro}many{{file_name} + # ficheiros}other{{file_name} + # ficheiros}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não existem pessoas recomendadas com quem partilhar"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicações"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta app não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ce63b94..7d5721a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -47,6 +47,7 @@
     <string name="enablePin" msgid="2543771964137091212">"Falha. Ative o bloqueio do chip/R-UIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
       <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
+      <item quantity="many">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
       <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
@@ -175,7 +176,7 @@
     <string name="low_memory" product="watch" msgid="3479447988234030194">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"O armazenamento do dispositivo Android TV está cheio. Exclua alguns arquivos para liberar espaço."</string>
     <string name="low_memory" product="default" msgid="2539532364144025569">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
-    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}other{Autoridades certificadoras instaladas}}"</string>
+    <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoridade certificadora instalada}one{Autoridade certificadora instalada}many{Autoridades certificadoras instaladas}other{Autoridades certificadoras instaladas}}"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Por terceiros desconhecidos"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo administrador do seu perfil de trabalho"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -249,7 +250,7 @@
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Use este recurso na maioria das circunstâncias. Ele permite que você acompanhe o progresso do relatório, informe mais detalhes sobre o problema e faça capturas de tela. É possível que ele omita algumas seções menos utilizadas que levam muito tempo na emissão dos relatórios."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Relatório completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Use esta opção para ter o mínimo de interferência do sistema quando seu dispositivo não estiver respondendo ou estiver muito lento, ou quando você precisar de todas as seções de relatórios. Ela não permite que você informe mais detalhes ou faça capturas de tela adicionais."</string>
-    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
+    <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}one{Capturas de tela para o relatório do bug vão ser feitas em # segundo.}many{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}other{Capturas de tela para o relatório do bug vão ser feitas em # segundos.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de tela com o relatório do bug concluída"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao capturar a tela com o relatório do bug"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
@@ -605,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operação de impressão digital cancelada."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operação de impressão digital cancelada pelo usuário."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Excesso de tentativas. Tente novamente mais tarde."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Excesso de tentativas. Use o bloqueio de tela."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
@@ -635,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Entre em contato com uma assistência técnica."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Falha ao criar o modelo de rosto. Tente de novo."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Muito iluminado. Diminua a iluminação."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Use uma iluminação mais intensa"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Afaste o smartphone"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Aproxime o smartphone do seu rosto"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Mova o smartphone para cima"</string>
@@ -1085,7 +1086,7 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar o Explorar por toque. Com ele, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone por gestos."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 mês atrás"</string>
     <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Antes de 1 mês atrás"</string>
-    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}other{Nos últimos # dias}}"</string>
+    <string name="last_num_days" msgid="2393660431490280537">"{count,plural, =1{No último # dia}one{No último # dia}many{Nos últimos # dias}other{Nos últimos # dias}}"</string>
     <string name="last_month" msgid="1528906781083518683">"Mês passado"</string>
     <string name="older" msgid="1645159827884647400">"Mais antigos"</string>
     <string name="preposition_for_date" msgid="2780767868832729599">"em <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -1112,14 +1113,14 @@
     <string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g>h"</string>
     <string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> dias"</string>
     <string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g>a"</string>
-    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}other{# minutos atrás}}"</string>
-    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}other{# horas atrás}}"</string>
-    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}other{# dias atrás}}"</string>
-    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}other{# anos atrás}}"</string>
-    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}other{# minutos}}"</string>
-    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}other{# horas}}"</string>
-    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}other{# dias}}"</string>
-    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}other{# anos}}"</string>
+    <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}many{# minutos atrás}other{# minutos atrás}}"</string>
+    <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}many{# horas atrás}other{# horas atrás}}"</string>
+    <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}many{# dias atrás}other{# dias atrás}}"</string>
+    <string name="duration_years_relative" msgid="8731202348869424370">"{count,plural, =1{# ano atrás}one{# ano atrás}many{# anos atrás}other{# anos atrás}}"</string>
+    <string name="duration_minutes_relative_future" msgid="5259574171747708115">"{count,plural, =1{# minuto}one{# minuto}many{# minutos}other{# minutos}}"</string>
+    <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# hora}one{# hora}many{# horas}other{# horas}}"</string>
+    <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# dia}one{# dia}many{# dias}other{# dias}}"</string>
+    <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# ano}one{# ano}many{# anos}other{# anos}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problema com o vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Este vídeo não é válido para transmissão neste dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Não é possível reproduzir este vídeo."</string>
@@ -1168,7 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
     <string name="selected" msgid="6614607926197755875">"selecionado"</string>
     <string name="not_selected" msgid="410652016565864475">"não selecionado"</string>
-    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 de {max} estrelas}one{# de {max} estrelas}other{# de {max} estrelas}}"</string>
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 de {max} estrelas}one{# de {max} estrelas}many{# de {max} estrelas}other{# de {max} estrelas}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"em andamento"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
@@ -1507,7 +1508,7 @@
     <string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
     <string name="no_matches" msgid="6472699895759164599">"Não encontrado"</string>
     <string name="find_on_page" msgid="5400537367077438198">"Localizar na página"</string>
-    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}other{# de {total}}}"</string>
+    <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# correspondência}one{# de {total}}many{# de {total}}other{# de {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Concluído"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Limpando armazenamento compartilhado…"</string>
     <string name="share" msgid="4157615043345227321">"Compartilhar"</string>
@@ -1611,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefone"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Alto-falantes na base"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Fones de ouvido"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string>
@@ -1860,14 +1861,14 @@
     <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você está usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não apareçam até você tocar nelas."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar a Economia de dados?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
-    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
-    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}other{Por # minutos}}"</string>
-    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}other{Por #min}}"</string>
-    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}other{Por # horas}}"</string>
-    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}other{Por #h}}"</string>
+    <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Por um minuto (até {formattedTime})}one{Por # minuto (até {formattedTime})}many{Por # minutos (até {formattedTime})}other{Por # minutos (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Por 1min (até {formattedTime})}one{Por #min (até {formattedTime})}many{Por #min (até {formattedTime})}other{Por #min (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Por 1 hora (até {formattedTime})}one{Por # hora (até {formattedTime})}many{Por # horas (até {formattedTime})}other{Por # horas (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_hours_summary_short" msgid="687919813833347945">"{count,plural, =1{Por 1h (até {formattedTime})}one{Por #h (até {formattedTime})}many{Por #h (até {formattedTime})}other{Por #h (até {formattedTime})}}"</string>
+    <string name="zen_mode_duration_minutes" msgid="2340007982276569054">"{count,plural, =1{Por um minuto}one{Por # minuto}many{Por # minutos}other{Por # minutos}}"</string>
+    <string name="zen_mode_duration_minutes_short" msgid="2435756450204526554">"{count,plural, =1{Por 1min}one{Por #min}many{Por #min}other{Por #min}}"</string>
+    <string name="zen_mode_duration_hours" msgid="7841806065034711849">"{count,plural, =1{Por 1 hora}one{Por # hora}many{Por # horas}other{Por # horas}}"</string>
+    <string name="zen_mode_duration_hours_short" msgid="3666949653933099065">"{count,plural, =1{Por 1h}one{Por #h}many{Por #h}other{Por #h}}"</string>
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
@@ -2000,7 +2001,7 @@
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salvar no Preenchimento automático"</string>
     <string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Não é possível preencher os conteúdos automaticamente"</string>
     <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Sem sugestões de preenchimento automático"</string>
-    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
+    <string name="autofill_picker_some_suggestions" msgid="5560549696296202701">"{count,plural, =1{Uma sugestão de preenchimento automático}one{# sugestão de preenchimento automático}many{# sugestões de preenchimento automático}other{# sugestões de preenchimento automático}}"</string>
     <string name="autofill_save_title" msgid="7719802414283739775">"Salvar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Salvar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Salvar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
@@ -2110,7 +2111,7 @@
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
     <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá ativado no modo avião"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Carregando"</string>
-    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}other{{file_name} + # arquivos}}"</string>
+    <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # arquivo}one{{file_name} + # arquivo}many{{file_name} + # arquivos}other{{file_name} + # arquivos}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Não há sugestões de pessoas para compartilhar"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de apps"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Este app não tem permissão de gravação, mas pode capturar áudio pelo dispositivo USB."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1e050e1..27b04d6 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -606,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operațiunea privind amprenta a fost anulată."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Operațiunea privind amprenta a fost anulată de utilizator."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Prea multe încercări. Încercați din nou mai târziu."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Prea multe încercări. Folosește blocarea ecranului."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Încercați din nou."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nu au fost înregistrate amprente."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string>
@@ -636,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizitați un furnizor de servicii de reparații."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nu se poate crea modelul facial. Reîncercați."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Prea luminos. Încercați o lumină mai slabă."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Încercați o lumină mai puternică"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Mutați telefonul mai departe"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Mutați telefonul mai aproape"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Mutați telefonul mai sus"</string>
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Difuz. dispozit. andocare"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Căști"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0f21c90..2cceafc 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Операция с отпечатком отменена."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Операция с отпечатком пальца отменена пользователем."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Слишком много попыток. Повторите позже."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Слишком много попыток. Используйте другой способ разблокировки экрана."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Повторите попытку."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Нет отсканированных отпечатков пальцев"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Обратитесь в сервисный центр."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Невозможно создать модель лица. Повторите попытку."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Слишком светло. Сделайте освещение менее ярким."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Сделайте освещение ярче"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Переместите телефон дальше от лица"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Переместите телефон ближе к лицу"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Переместите телефон выше"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевизор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Динамики док-станции"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Наушники"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Система"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index e96e0e4..06ac0f8 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ඇඟිලි සලකුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"පරිශීලක විසින් ඇඟිලි සලකුණු මෙහෙයුම අවසන් කරන ලදී."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"උත්සාහයන් ඉතා වැඩි ගණනකි. කරුණාකර පසුව නැවත උත්සාහ කරන්න."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"උත්සාහ ගණන ඉතා වැඩියි. ඒ වෙනුවට තිර අගුල භාවිත කරන්න."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"නැවත උත්සාහ කරන්න."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ඇඟිලි සලකුණු ඇතුළත් කර නොමැත."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"අළුත්වැඩියා සැපයුම්කරුවෙකු බලන්න."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"ඔබගේ මුහුණු ආකෘතිය තැනිය නොහැකිය. නැවත උත්සාහ කරන්න."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"දීප්තිය වැඩියි. තවත් මඳ ආලෝකය උත්සාහ කරන්න."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"තවත් දීප්තිමත් ආලෝකය උත්සාහ කරන්න"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"දුරකථනය තවත් ඈතට ගෙන යන්න"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"දුරකථනය තවත් සමීපයට ගෙන එන්න"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"දුරකථනය තවත් ඉහළට ගෙන යන්න"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"රූපවාහිනී"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"දුරකථනය"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"නාදක ඩොක් කරන්න"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ඉස් බණු"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"පද්ධතිය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 566f448..cdc6829 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operácia týkajúca sa odtlačku prsta bola zrušená"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Overenie odtlačku prsta zrušil používateľ."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Príliš veľa pokusov. Skúste to neskôr."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Príliš veľa pokusov. Použite radšej zámku obrazovky."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Skúste to znova"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neregistrovali ste žiadne odtlačky prstov."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Navštívte poskytovateľa opráv."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Model tváre sa nedá vytvoriť. Skúste to znova."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Príliš veľa svetla. Skúste jemnejšie osvetlenie."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Skúste lepšie osvetlenie"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Oddiaľte telefón"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Priblížte telefón"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Posuňte telefón vyššie"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televízor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefón"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Reproduktory doku"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slúchadlá"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Systém"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index af74eba..6da07f8 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Dejanje s prstnim odtisom je bilo preklicano."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Dejanje s prstnim odtisom je preklical uporabnik."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Preveč poskusov. Poskusite znova pozneje."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Preveč poskusov. Odklenite z zaklepanjem zaslona."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Poskusite znova."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Obiščite ponudnika popravil."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Modela obraza ni mogoče ustvariti. Poskusite znova."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvetlo. Poskusite z blažjo osvetlitvijo."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Poskusite z močnejšo osvetlitvijo."</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefon nekoliko odmaknite."</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Bolj približajte telefon."</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefon premaknite višje."</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televizor"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Zvočniki stojala"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Slušalke"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index c359aad..587215a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Operacioni i gjurmës së gishtit u anulua."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Veprimi i gjurmës së gishtit u anulua nga përdoruesi."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Keni bërë shumë tentativa. Provo përsëri më vonë."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Shumë përpjekje. Përdor më mirë kyçjen e ekranit."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Provo përsëri."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nuk ka asnjë gjurmë gishti të regjistruar."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizito një ofrues të shërbimit të riparimit."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Modeli i fytyrës nuk krijohet. Provo sërish."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Me shumë ndriçim. Provo një ndriçim më të butë."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Provo një ndriçim më të fortë"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Lëvize telefonin më larg"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Lëvize telefonin më afër"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Lëvize telefonin më lart"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televizori"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Altoparlantët e stacionit"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kufjet"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistemi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6d29046..2acaf5c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -606,8 +606,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Радња са отиском прста је отказана."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Корисник је отказао радњу са отиском прста."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Превише покушаја. Пробајте поново касније."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Превише покушаја. Користите закључавање екрана уместо тога."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Пробајте поново."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Није регистрован ниједан отисак прста."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string>
@@ -636,7 +635,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Посетите добављача за поправке."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Прављење модела лица није успело. Пробајте поново."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Превише је светло. Пробајте са слабијим осветљењем."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Пробајте са јачим осветљењем"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Удаљите телефон"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Приближите телефон"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Померите телефон нагоре"</string>
@@ -1612,7 +1612,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ТВ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Звучници базне станице"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Слушалице"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Систем"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1ee3192..a6c162a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingeravtrycksåtgärden avbröts."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingeravtrycksåtgärden avbröts av användaren."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Du har gjort för många försök. Försök igen senare."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"För många försök. Använd låsskärmen i stället."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Försök igen."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Inga fingeravtryck har registrerats."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Besök ett reparationsställe."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ansiktsmodellen kunde inte skapas. Försök igen."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Det är för ljust. Testa lägre belysning."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Testa med bättre belysning"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Flytta telefonen längre bort"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"För telefonen närmare"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Höj telefonen"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Mobil"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Dockningsstationens högtalare"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Hörlurar"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8659b6a..b17f58e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Mchakato wa alama ya kidole umeghairiwa."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Mtumiaji ameghairi uthibitishaji wa alama ya kidole."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Majaribio mengi mno. Jaribu tena baadaye."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Umejaribu mara nyingi mno. Badala yake, tumia mbinu ya kufunga skrini."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Jaribu tena."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hakuna alama za vidole zilizojumuishwa."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Tembelea mtoa huduma za urekebishaji."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Imeshindwa kuunda muundo wa uso wako. Jaribu tena."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Inang\'aa mno. Jaribu mwangaza hafifu"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Jaribu kuongeza mwangaza"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Sogeza simu mbali kiasi"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Sogeza simu karibu"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Sogeza simu juu zaidi"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Runinga"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Simu"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Vipasa sauti vya kituo"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Vipokeasauti"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Mfumo"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 611eadf..6a7973e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"கைரேகை செயல்பாடு ரத்துசெய்யப்பட்டது."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"பயனர், கைரேகை உறுதிப்படுத்துதலை ரத்துசெய்தார்."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"அதிகமான முயற்சிகள். பிறகு முயற்சிக்கவும்."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"பலமுறை முயன்றுவிட்டீர்கள். இதற்குப் பதிலாகத் திரைப்பூட்டைப் பயன்படுத்தவும்."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"மீண்டும் முயற்சிக்கவும்."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"கைரேகைப் பதிவுகள் எதுவும் இல்லை."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"பழுதுபார்ப்புச் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"முகத் தோற்றம் பதிவாகவில்லை. மீண்டும் முயலவும்."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"அதிக ஒளிர்வு. மிதமான ஒளியில் முயலவும்."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"பிரகாசமான ஒளியில் முயலவும்"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"மொபைலை முகத்தில் இருந்து தள்ளிப் பிடிக்கவும்"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"மொபைலை அருகில் நகர்த்தவும்"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"மொபைலை மேலே நகர்த்தவும்"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"டிவி"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ஃபோன்"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"மொபைல் வைக்கும் கருவியின் ஸ்பீக்கர்கள்"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ஹெட்ஃபோன்கள்"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"சிஸ்டம்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index a56a628..8c53b13 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"వేలిముద్ర యాక్టివిటీ రద్దయింది."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేశారు."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"చాలా ఎక్కువ సార్లు ప్రయత్నించారు. బదులుగా స్క్రీన్ లాక్‌ను ఉపయోగించండి."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"మళ్లీ ప్రయత్నించండి."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"రిపెయిర్ ప్రొవైడర్‌ను సందర్శించండి."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"మీ ఫేస్‌మోడల్ క్రియేషన్ కుదరదు. మళ్లీ ట్రై చేయండి."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"వెలుతురు అధికంగా ఉంది. తక్కువ ఉండేలా చూడండి."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ప్రకాశవంతమైన లైటింగ్‌లో ట్రై చేయండి"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ఫోన్‌ను కాస్త దూరంగా జరపండి"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ఫోన్‌ను దగ్గరగా పట్టుకోండి"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ఫోన్‌ను పైకి పట్టుకోండి"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"టీవీ"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ఫోన్"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"డాక్ స్పీకర్‌లు"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"హెడ్‌ఫోన్‌లు"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"సిస్టమ్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a51876c..7826774 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"ยกเลิกการทำงานของลายนิ้วมือ"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"ผู้ใช้ยกเลิกการทำงานของลายนิ้วมือ"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"ลองหลายครั้งเกินไป ใช้การล็อกหน้าจอแทน"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ลองอีกครั้ง"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ไม่มีลายนิ้วมือที่ลงทะเบียน"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"โปรดติดต่อผู้ให้บริการซ่อม"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"สร้างรูปแบบใบหน้าไม่ได้ โปรดลองอีกครั้ง"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"สว่างเกินไป ลองหาตำแหน่งที่แสงน้อยกว่านี้"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"ลองหาตำแหน่งที่สว่างขึ้น"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"ถือโทรศัพท์ให้ห่างกว่านี้"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"ถือโทรศัพท์ให้ใกล้กว่านี้"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"ยกโทรศัพท์ให้สูงขึ้น"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"ทีวี"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"โทรศัพท์"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ลำโพงแท่นชาร์จ"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"หูฟัง"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"ระบบ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index faacade..e9d17a9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Nakansela ang operasyong ginagamitan ng fingerprint."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Kinansela ng user ang operasyon sa fingerprint."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Napakaraming pagtatangka. Subukan ulit sa ibang pagkakataon."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Masyadong maraming pagsubok. Gamitin na lang ang lock ng screen."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Subukang muli."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bumisita sa provider ng pag-aayos."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Hindi magawa ang iyong face model. Subukan ulit."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Masyadong maliwanag. Subukang bawasan ang liwanag."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Subukan sa mas maliwanag"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Ilayo pa ang telepono"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Ilapit pa ang telepono"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Itaas pa ang telepono"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telepono"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Mga speaker ng dock"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Mga Headphone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"System"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index af503ca..762b731 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Parmak izi işlemi iptal edildi."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Parmak izi işlemi kullanıcı tarafından iptal edildi."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Çok fazla deneme yapıldı. Bunun yerine ekran kilidini kullanın."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tekrar deneyin."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Parmak izi kaydedilmedi."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Bir onarım hizmeti sağlayıcıyı ziyaret edin."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Yüzünüzün modeli oluşturulamıyor. Tekrar deneyin."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Çok parlak. Parlaklığı daha az bir ışıklandırma deneyin."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Daha parlak ışıkta deneyin"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonu uzaklaştırın"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonu yaklaştırın"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonu daha yukarı kaldırın"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Yuva hoparlörleri"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Kulaklıklar"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistem"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bac234a..730cfac 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -607,8 +607,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Дію з відбитком пальця скасовано."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Користувач скасував дію з відбитком пальця."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Забагато спроб. Спробуйте пізніше."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Забагато спроб. Використайте натомість розблокування екрана."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Повторіть спробу."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Відбитки пальців не зареєстровано."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string>
@@ -637,7 +636,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Зверніться до постачальника послуг із ремонту."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Модель обличчя не створено. Повторіть спробу."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Занадто яскраво. Потрібно менше світла."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Потрібно більше світла"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Тримайте телефон далі від обличчя"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Тримайте телефон ближче до обличчя"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Підніміть телефон вище"</string>
@@ -1613,7 +1613,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Телевізор"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Телефон"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Динаміки док-станції"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Навушники"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Система"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7db1619..6fa0071 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"فنگر پرنٹ کی کارروائی منسوخ ہوگئی۔"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"صارف نے فنگر پرنٹ کی کارروائی منسوخ کر دی۔"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوبارہ کوشش کریں۔"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"کافی زیادہ کوششیں۔ اس کے بجائے اسکرین لاک کا استعمال کریں۔"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"دوبارہ کوشش کریں۔"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"کوئی فنگر پرنٹ مندرج شدہ نہیں ہے۔"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"ایک مرمت فراہم کنندہ کو ملاحظہ کریں۔"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"آپکے چہرے کا ماڈل تخلیق نہیں ہو سکا۔ پھر کوشش کریں۔"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"کافی روشنی ہے۔ ہلکی روشنی میں آزمائیں۔"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"تیز روشنی میں آزمائیں"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"فون کو تھوڑا دور کریں"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"فون کو تھوڑا قریب کریں"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"فون کو تھوڑا اوپر لے جائیں"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"فون"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"ڈاک اسپیکرز"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"ہیڈ فونز"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"سسٹم"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 8f4cceb..b9a0ae5 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Barmoq izi tekshiruvi bekor qilindi."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Barmoq izi amali foydalanuvchi tomonidan bekor qilindi"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Urinishlar soni ko‘payib ketdi. Keyinroq qayta urinib ko‘ring."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Juda koʻp urinildi. Ekran qulfi orqali urining."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Qayta urinib ko‘ring."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hech qanday barmoq izi qayd qilinmagan."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu qurilmada barmoq izi skaneri mavjud emas."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Xizmat koʻrsatish markaziga murojaat qiling."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Yuzingiz modeli yaratilmadi. Qayta urining."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Juda yorqin. Biroz soyaroq joy tanlang."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Atrofingizni yanada yoriting"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Telefonni biroz uzoqroq tuting"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Telefonni yaqinroq tuting"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Telefonni teparoq tuting"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefon"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Taglik karnaylar"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Quloq karnaychalari"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Tizim"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 40eb56d..ad4a3899 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Thao tác dùng dấu vân tay bị hủy."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Người dùng đã hủy thao tác dùng dấu vân tay."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Quá nhiều lần thử. Hãy thử lại sau."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Bạn đã thử quá nhiều lần. Hãy dùng phương thức khoá màn hình."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Thử lại."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Hãy liên hệ với một nhà cung cấp dịch vụ sửa chữa."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Không thể tạo mẫu khuôn mặt của bạn. Hãy thử lại."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Quá sáng. Hãy thử giảm độ sáng."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Hãy thử tăng độ sáng"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Đưa điện thoại ra xa hơn"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Đưa điện thoại lại gần hơn"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Nâng điện thoại lên cao hơn"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Điện thoại"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Loa đế"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Tai nghe"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Hệ thống"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 066600b..ce5cd53 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"指纹操作已取消。"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"用户取消了指纹操作。"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"尝试次数过多,请稍后重试。"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"尝试次数过多,请通过屏幕锁定功能解锁。"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"请重试。"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未注册任何指纹。"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"请联系维修服务提供商。"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"无法创建您的脸部模型,请重试。"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"亮度过高,请尝试使用较柔和的亮度。"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"请尝试调亮光线"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"请将手机拿远一点"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"请将手机拿近一点"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"请将手机举高一点"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"电视"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"手机"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"基座扬声器"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"耳机"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"系统"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a1c0921f..96c7b0b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋操作已取消。"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"使用者已取消指紋操作。"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"嘗試次數過多,請稍後再試。"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"嘗試次數過多,請改用螢幕鎖定功能。"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"再試一次。"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未註冊任何指紋"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"請諮詢維修服務供應商。"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"無法建立面部模型,請再試一次。"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"影像太亮。請嘗試在更暗的環境下使用。"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"請試用更充足的光線"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"請將手機移開一點"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"請將手機移近一點"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"請將手機向上移"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"電視"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"手機"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"插座喇叭"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"耳機"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"系統"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index cb8f7bf..46d95c7f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"指紋作業已取消。"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"使用者已取消指紋驗證作業。"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"嘗試次數過多,請稍後再試。"</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"嘗試次數過多,請改用螢幕鎖定功能。"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"請再試一次。"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未登錄任何指紋。"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"請洽詢維修供應商。"</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"無法建立臉部模型,請再試一次。"</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"亮度過高,請嘗試使用較柔和的照明方式。"</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"請採用更明亮的光源"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"請將手機拿遠一點"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"請將手機拿近一點"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"請將手機舉高一點"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"電視"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"手機"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"座架喇叭"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"耳機"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"系統"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 5ae40dc..6e640c6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -605,8 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Ukusebenza kwezigxivizo zeminwe kukhanseliwe."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Umsebenzi wezigxivizo zomunwe ukhanselwe umsebenzisi."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
-    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
-    <skip />
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Imizamo eminingi kakhulu. Sebenzisa ukukhiya isikrini kunalokho."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Zama futhi."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Azikho izigxivizo zeminwe ezibhalisiwe."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string>
@@ -635,7 +634,8 @@
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vakashela umhlinzeki wokulungisa."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Ayikwazi ukusungula imodeli yobuso bakho. Zama futhi."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Kukhanya kakhulu. Zama ukukhanya okuthambile."</string>
-    <string name="face_acquired_too_dark" msgid="7919016380747701228">"Zama ukukhanyisa okukhudlwana"</string>
+    <!-- no translation found for face_acquired_too_dark (8539853432479385326) -->
+    <skip />
     <string name="face_acquired_too_close" msgid="4453646176196302462">"Yisa ifoni kude"</string>
     <string name="face_acquired_too_far" msgid="2922278214231064859">"Sondeza ifoni eduze"</string>
     <string name="face_acquired_too_high" msgid="8278815780046368576">"Yisa ifoni phezulu"</string>
@@ -1611,7 +1611,7 @@
     <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"I-TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Ifoni"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Izipikha ze-Dock"</string>
-    <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
+    <string name="default_audio_route_name_external_device" msgid="5474470558160717850">"HDMI"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Ama-headphone"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"I-USB"</string>
     <string name="default_audio_route_category_name" msgid="5241740395748134483">"Isistimu"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c7153fc..69c5043 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4509,6 +4509,8 @@
         </attr>
     </declare-styleable>
     <declare-styleable name="EditText">
+        <!-- Enables styling shortcuts, e.g. Ctrl+B for bold. This is off by default.  -->
+        <attr name="enableTextStylingShortcuts" format="boolean" />
     </declare-styleable>
     <declare-styleable name="FastScroll">
         <!-- Drawable used for the scroll bar thumb. -->
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index fe296c7..4b27bf2 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -18,6 +18,7 @@
     <bool name="kg_enable_camera_default_widget">true</bool>
     <bool name="kg_center_small_widgets_vertically">false</bool>
     <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
+    <bool name="kg_wake_on_acquire_start">false</bool>
     <bool name="action_bar_embed_tabs">true</bool>
     <bool name="split_action_bar_is_narrow">true</bool>
     <bool name="preferences_prefer_dual_pane">false</bool>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f685415..dfada13 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1733,7 +1733,7 @@
     <item name="default_lock_wallpaper" type="drawable">@null</item>
 
     <!-- Component name of the built in wallpaper used to display bitmap wallpapers. This must not be null. -->
-    <string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.ImageWallpaper</string>
+    <string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.wallpapers.ImageWallpaper</string>
 
     <!-- True if WallpaperService is enabled -->
     <bool name="config_enableWallpaperService">true</bool>
diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml
new file mode 100644
index 0000000..8ed58f3
--- /dev/null
+++ b/core/res/res/values/config_device_idle.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds.  Do not translate.
+
+     NOTE: The naming convention is "config_camelCaseValue". Some legacy
+     entries do not follow the convention, but all new entries should. -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Default for DeviceIdleController.Constants.FLEX_TIME_SHORT -->
+    <integer name="device_idle_flex_time_short_ms">60000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT -->
+    <integer name="device_idle_light_after_inactive_to_ms">180000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_TIMEOUT -->
+    <integer name="device_idle_light_idle_to_ms">300000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_FACTOR -->
+    <item name="device_idle_light_idle_factor" format="float" type="integer">2.0</item>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_MAX_IDLE_TIMEOUT -->
+    <integer name="device_idle_light_max_idle_to_ms">900000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET -->
+    <integer name="device_idle_light_idle_maintenance_min_budget_ms">60000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET -->
+    <integer name="device_idle_light_idle_maintenance_max_budget_ms">300000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MIN_LIGHT_MAINTENANCE_TIME -->
+    <integer name="device_idle_min_light_maintenance_time_ms">5000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MIN_DEEP_MAINTENANCE_TIME -->
+    <integer name="device_idle_min_deep_maintenance_time_ms">30000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.INACTIVE_TIMEOUT -->
+    <integer name="device_idle_inactive_to_ms">1800000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.SENSING_TIMEOUT -->
+    <integer name="device_idle_sensing_to_ms">240000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LOCATING_TIMEOUT -->
+    <integer name="device_idle_locating_to_ms">30000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.LOCATION_ACCURACY -->
+    <item name="device_idle_location_accuracy" format="float" type="integer">20.0</item>
+
+    <!-- Default for DeviceIdleController.Constants.MOTION_INACTIVE_TIMEOUT -->
+    <integer name="device_idle_motion_inactive_to_ms">600000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MOTION_INACTIVE_TIMEOUT_FLEX -->
+    <integer name="device_idle_motion_inactive_to_flex_ms">60000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.IDLE_AFTER_INACTIVE_TIMEOUT -->
+    <integer name="device_idle_idle_after_inactive_to_ms">1800000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.IDLE_PENDING_TIMEOUT -->
+    <integer name="device_idle_idle_pending_to_ms">300000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MAX_IDLE_PENDING_TIMEOUT -->
+    <integer name="device_idle_max_idle_pending_to_ms">600000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.IDLE_PENDING_FACTOR -->
+    <item name="device_idle_idle_pending_factor" format="float" type="integer">2.0</item>
+
+    <!-- Default for DeviceIdleController.Constants.QUICK_DOZE_DELAY_TIMEOUT -->
+    <integer name="device_idle_quick_doze_delay_to_ms">60000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.IDLE_TIMEOUT -->
+    <integer name="device_idle_idle_to_ms">3600000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MAX_IDLE_TIMEOUT -->
+    <integer name="device_idle_max_idle_to_ms">21600000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.IDLE_FACTOR -->
+    <item name="device_idle_idle_factor" format="float" type="integer">2.0</item>
+
+    <!-- Default for DeviceIdleController.Constants.MIN_TIME_TO_ALARM -->
+    <integer name="device_idle_min_time_to_alarm_ms">3600000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MAX_TEMP_APP_ALLOWLIST_DURATION_MS -->
+    <integer name="device_idle_max_temp_app_allowlist_duration_ms">300000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.MMS_TEMP_APP_ALLOWLIST_DURATION_MS -->
+    <integer name="device_idle_mms_temp_app_allowlist_duration_ms">60000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.SMS_TEMP_APP_ALLOWLIST_DURATION_MS -->
+    <integer name="device_idle_sms_temp_app_allowlist_duration_ms">20000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.NOTIFICATION_ALLOWLIST_DURATION_MS -->
+    <integer name="device_idle_notification_allowlist_duration_ms">30000</integer>
+
+    <!-- Default for DeviceIdleController.Constants.WAIT_FOR_UNLOCK -->
+    <bool name="device_idle_wait_for_unlock">true</bool>
+
+    <!-- Default for DeviceIdleController.Constants.PRE_IDLE_FACTOR_LONG -->
+    <item name="device_idle_pre_idle_factor_long" format="float" type="integer">1.67</item>
+
+    <!-- Default for DeviceIdleController.Constants.PRE_IDLE_FACTOR_SHORT -->
+    <item name="device_idle_pre_idle_factor_short" format="float" type="integer">0.33</item>
+
+    <!-- Default for DeviceIdleController.Constants.USE_WINDOW_ALARMS -->
+    <bool name="device_idle_use_window_alarms">true</bool>
+</resources>
+
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 1327d96..ea2b988 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -17,12 +17,6 @@
 <resources>
     <!-- This file defines Android telephony related resources -->
 
-    <!-- Whether force disabling telephony new data stack or not.
-         This flag and the old data stack code will be deleted in Android 14.
-    -->
-    <bool name="config_force_disable_telephony_new_data_stack">false</bool>
-    <java-symbol type="bool" name="config_force_disable_telephony_new_data_stack" />
-
     <!-- Configure tcp buffer sizes per network type in the form:
          network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
 
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 082acbe..4ddbf58 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -70,6 +70,12 @@
   <item type="id" name="cut" />
   <item type="id" name="copy" />
   <item type="id" name="paste" />
+  <!-- Editor action that makes selected text bold. -->
+  <item type="id" name="bold" />
+  <!-- Editor action that makes selected text italic. -->
+  <item type="id" name="italic" />
+  <!-- Editor action that makes selected text underline. -->
+  <item type="id" name="underline" />
   <item type="id" name="copyUrl" />
   <item type="id" name="selectTextMode" />
   <item type="id" name="switchInputMethod" />
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index ad7d03e..89741ef 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -115,9 +115,13 @@
     <public name="handwritingBoundsOffsetRight" />
     <public name="handwritingBoundsOffsetBottom" />
     <public name="accessibilityDataPrivate" />
+    <public name="enableTextStylingShortcuts" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01cd0000">
+    <public name="bold" />
+    <public name="italic" />
+    <public name="underline" />
   </staging-public-group>
 
   <staging-public-group type="style" first-id="0x01cc0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8488b68..9214f43 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1689,7 +1689,7 @@
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
     <string name="fingerprint_acquired_partial">Press firmly on the sensor</string>
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
-    <string name="fingerprint_acquired_insufficient">Couldn\'t process fingerprint. Please try again.</string>
+    <string name="fingerprint_acquired_insufficient">Can\u2019t recognize fingerprint. Try again.</string>
     <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
     <string name="fingerprint_acquired_imager_dirty">Clean fingerprint sensor and try again</string>
     <string name="fingerprint_acquired_imager_dirty_alt">Clean sensor and try again</string>
@@ -1701,6 +1701,8 @@
     <string name="fingerprint_acquired_already_enrolled">Try another fingerprint</string>
     <!-- Message shown during fingerprint acquisition when fingerprint sensor detected too much light.[CHAR LIMIT=50] -->
     <string name="fingerprint_acquired_too_bright">Too bright</string>
+    <!-- Message shown during fingerprint acquisition when a Power press has been detected.[CHAR LIMIT=50] -->
+    <string name="fingerprint_acquired_power_press">Power press detected</string>
     <!-- Message shown during fingerprint acquisition when a fingerprint must be adjusted.[CHAR LIMIT=50] -->
     <string name="fingerprint_acquired_try_adjusting">Try adjusting</string>
     <!-- Message shown during fingerprint acquisition when a fingeprint area has already been captured during enrollment [CHAR LIMIT=100] -->
@@ -1725,17 +1727,17 @@
     <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
     <string name="fingerprint_error_no_space">Can\u2019t set up fingerprint</string>
     <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
-    <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+    <string name="fingerprint_error_timeout">Fingerprint setup timed out. Try again.</string>
     <!-- Generic error message shown when the fingerprint operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user-->
     <string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
     <!-- Generic error message shown when the fingerprint authentication operation is canceled due to user input. Generally not shown to the user -->
     <string name="fingerprint_error_user_canceled">Fingerprint operation canceled by user.</string>
     <!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
-    <string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
+    <string name="fingerprint_error_lockout">Too many attempts. Use screen lock instead.</string>
     <!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
     <string name="fingerprint_error_lockout_permanent">Too many attempts. Use screen lock instead.</string>
     <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
-    <string name="fingerprint_error_unable_to_process">Try again.</string>
+    <string name="fingerprint_error_unable_to_process">Can\u2019t process fingerprint. Try again.</string>
     <!-- Generic error message shown when the user has no enrolled fingerprints -->
     <string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string>
     <!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor -->
@@ -1797,7 +1799,7 @@
     <!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
     <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
     <!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_dark">Try brighter lighting</string>
+    <string name="face_acquired_too_dark">Not enough light</string>
     <!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
     <string name="face_acquired_too_close">Move phone farther away</string>
     <!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
@@ -3574,11 +3576,11 @@
 
     <!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
     is pressed during fingerprint enrollment. -->
-    <string name="fp_power_button_enrollment_title">Tap to turn off screen</string>
+    <string name="fp_power_button_enrollment_title">To end setup, turn off screen</string>
 
     <!-- [CHAR LIMIT=20] Positive button of dialog shown to confirm device going to sleep if the
     power button is pressed during fingerprint enrollment. -->
-    <string name="fp_power_button_enrollment_button_text">Turn off screen</string>
+    <string name="fp_power_button_enrollment_button_text">Turn off</string>
 
     <!-- [CHAR LIMIT=40] Title of dialog shown to confirm device going to sleep if the power button
     is pressed during biometric prompt when a side fingerprint sensor is present. -->
@@ -4525,8 +4527,8 @@
     <!-- Name of the default audio route when an audio dock is connected. [CHAR LIMIT=50] -->
     <string name="default_audio_route_name_dock_speakers">Dock speakers</string>
 
-    <!-- Name of the default audio route when HDMI is connected. [CHAR LIMIT=50] -->
-    <string name="default_audio_route_name_hdmi">HDMI</string>
+    <!-- Name of the default audio route when an external device is connected. [CHAR LIMIT=50] -->
+    <string name="default_audio_route_name_external_device">External Device</string>
 
     <!-- Name of the default audio route when wired headphones are
          connected. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5db96a..7e8423a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1082,7 +1082,7 @@
   <java-symbol type="string" name="default_audio_route_id" />
   <java-symbol type="string" name="default_audio_route_name" />
   <java-symbol type="string" name="default_audio_route_name_dock_speakers" />
-  <java-symbol type="string" name="default_audio_route_name_hdmi" />
+  <java-symbol type="string" name="default_audio_route_name_external_device" />
   <java-symbol type="string" name="default_audio_route_name_headphones" />
   <java-symbol type="string" name="default_audio_route_name_usb" />
   <java-symbol type="string" name="default_audio_route_category_name" />
@@ -2611,6 +2611,7 @@
   <java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
   <java-symbol type="string" name="fingerprint_acquired_too_slow" />
   <java-symbol type="string" name="fingerprint_acquired_too_fast" />
+  <java-symbol type="string" name="fingerprint_acquired_power_press" />
   <java-symbol type="string" name="fingerprint_acquired_too_bright" />
   <java-symbol type="array" name="fingerprint_acquired_vendor" />
   <java-symbol type="string" name="fingerprint_error_canceled" />
@@ -2830,6 +2831,7 @@
   <java-symbol type="dimen" name="fast_scroller_minimum_touch_target" />
   <java-symbol type="array" name="config_cdma_international_roaming_indicators" />
   <java-symbol type="string" name="kg_text_message_separator" />
+  <java-symbol type="bool" name="kg_wake_on_acquire_start" />
 
   <java-symbol type="bool" name="config_use_sim_language_file" />
   <java-symbol type="bool" name="config_LTE_eri_for_network_name" />
@@ -4288,6 +4290,7 @@
   <java-symbol type="id" name="conversation_icon_badge_ring" />
   <java-symbol type="id" name="conversation_icon_badge_bg" />
   <java-symbol type="id" name="expand_button_container" />
+  <java-symbol type="id" name="expand_button_a11y_container" />
   <java-symbol type="id" name="expand_button_touch_container" />
   <java-symbol type="id" name="messaging_group_content_container" />
   <java-symbol type="id" name="expand_button_and_content_container" />
@@ -4411,6 +4414,40 @@
 
   <java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
 
+  <!-- To config device idle -->
+  <java-symbol type="integer" name="device_idle_flex_time_short_ms" />
+  <java-symbol type="integer" name="device_idle_light_after_inactive_to_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_to_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_factor" />
+  <java-symbol type="integer" name="device_idle_light_max_idle_to_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_maintenance_min_budget_ms" />
+  <java-symbol type="integer" name="device_idle_light_idle_maintenance_max_budget_ms" />
+  <java-symbol type="integer" name="device_idle_min_light_maintenance_time_ms" />
+  <java-symbol type="integer" name="device_idle_min_deep_maintenance_time_ms" />
+  <java-symbol type="integer" name="device_idle_inactive_to_ms" />
+  <java-symbol type="integer" name="device_idle_sensing_to_ms" />
+  <java-symbol type="integer" name="device_idle_locating_to_ms" />
+  <java-symbol type="integer" name="device_idle_location_accuracy" />
+  <java-symbol type="integer" name="device_idle_motion_inactive_to_ms" />
+  <java-symbol type="integer" name="device_idle_motion_inactive_to_flex_ms" />
+  <java-symbol type="integer" name="device_idle_idle_after_inactive_to_ms" />
+  <java-symbol type="integer" name="device_idle_idle_pending_to_ms" />
+  <java-symbol type="integer" name="device_idle_max_idle_pending_to_ms" />
+  <java-symbol type="integer" name="device_idle_idle_pending_factor" />
+  <java-symbol type="integer" name="device_idle_quick_doze_delay_to_ms" />
+  <java-symbol type="integer" name="device_idle_idle_to_ms" />
+  <java-symbol type="integer" name="device_idle_max_idle_to_ms" />
+  <java-symbol type="integer" name="device_idle_idle_factor" />
+  <java-symbol type="integer" name="device_idle_min_time_to_alarm_ms" />
+  <java-symbol type="integer" name="device_idle_max_temp_app_allowlist_duration_ms" />
+  <java-symbol type="integer" name="device_idle_mms_temp_app_allowlist_duration_ms" />
+  <java-symbol type="integer" name="device_idle_sms_temp_app_allowlist_duration_ms" />
+  <java-symbol type="integer" name="device_idle_notification_allowlist_duration_ms" />
+  <java-symbol type="bool" name="device_idle_wait_for_unlock" />
+  <java-symbol type="integer" name="device_idle_pre_idle_factor_long" />
+  <java-symbol type="integer" name="device_idle_pre_idle_factor_short" />
+  <java-symbol type="bool" name="device_idle_use_window_alarms" />
+
   <!-- Binder heavy hitter watcher configs -->
   <java-symbol type="bool" name="config_defaultBinderHeavyHitterWatcherEnabled" />
   <java-symbol type="integer" name="config_defaultBinderHeavyHitterWatcherBatchSize" />
diff --git a/core/tests/coretests/res/xml/power_profile_test_power_brackets.xml b/core/tests/coretests/res/xml/power_profile_test_power_brackets.xml
new file mode 100644
index 0000000..c129388
--- /dev/null
+++ b/core/tests/coretests/res/xml/power_profile_test_power_brackets.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<device name="Android">
+
+    <array name="cpu.clusters.cores">
+        <value>1</value>
+        <value>2</value>
+    </array>
+
+    <array name="cpu.core_speeds.cluster0">
+        <value>300000</value>
+    </array>
+
+    <array name="cpu.core_speeds.cluster1">
+        <value>300000</value>
+        <value>1000000</value>
+    </array>
+
+    <array name="cpu.core_power.cluster0">
+        <value>10</value>
+    </array>
+
+    <array name="cpu.core_power.cluster1">
+        <value>25</value>
+        <value>35</value>
+    </array>
+
+    <array name="cpu.power_brackets.cluster0">
+        <value>1</value>
+    </array>
+
+    <array name="cpu.power_brackets.cluster1">
+        <value>1</value>
+        <value>0</value>
+    </array>
+</device>
diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
index 2a3da05..625c66a 100644
--- a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
+++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
@@ -17,9 +17,11 @@
 package android.app;
 
 import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
 
 import android.os.Parcel;
 import android.test.AndroidTestCase;
+import android.text.TextUtils;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -70,4 +72,18 @@
         assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH,
                 fromParcel.getDescription().length());
     }
+
+    @Test
+    public void testNullableFields() {
+        NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", null);
+
+        Parcel parcel = Parcel.obtain();
+        group.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        NotificationChannelGroup fromParcel =
+                NotificationChannelGroup.CREATOR.createFromParcel(parcel);
+        assertEquals(group.getId(), fromParcel.getId());
+        assertTrue(TextUtils.isEmpty(fromParcel.getName()));
+    }
 }
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a2d4baf..4011933 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -33,6 +33,7 @@
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.ActivityThread.ActivityClientRecord;
+import android.app.Application;
 import android.app.IApplicationThread;
 import android.app.PictureInPictureParams;
 import android.app.ResourcesManager;
@@ -46,6 +47,7 @@
 import android.app.servertransaction.StopActivityItem;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
@@ -178,6 +180,85 @@
     }
 
     @Test
+    public void testOverrideScale() throws Exception {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+        final Application app = activity.getApplication();
+        final ActivityThread activityThread = activity.getActivityThread();
+        final IApplicationThread appThread = activityThread.getApplicationThread();
+        final DisplayMetrics originalAppMetrics = new DisplayMetrics();
+        originalAppMetrics.setTo(app.getResources().getDisplayMetrics());
+        final Configuration originalAppConfig =
+                new Configuration(app.getResources().getConfiguration());
+        final DisplayMetrics originalActivityMetrics = new DisplayMetrics();
+        originalActivityMetrics.setTo(activity.getResources().getDisplayMetrics());
+        final Configuration originalActivityConfig =
+                new Configuration(activity.getResources().getConfiguration());
+
+        final Configuration newConfig = new Configuration(originalAppConfig);
+        newConfig.seq = BASE_SEQ + 1;
+        newConfig.smallestScreenWidthDp++;
+
+        final float originalScale = CompatibilityInfo.getOverrideInvertedScale();
+        float scale = 0.5f;
+        CompatibilityInfo.setOverrideInvertedScale(scale);
+        try {
+            // Send process level config change.
+            ClientTransaction transaction = newTransaction(activityThread, null);
+            transaction.addCallback(ConfigurationChangeItem.obtain(new Configuration(newConfig)));
+            appThread.scheduleTransaction(transaction);
+            InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+            assertScreenScale(scale, app, originalAppConfig, originalAppMetrics);
+            // The activity's config doesn't change because ConfigurationChangeItem is process level
+            // that won't affect activity's override config.
+            assertEquals(originalActivityConfig.densityDpi,
+                    activity.getResources().getConfiguration().densityDpi);
+
+            scale = 0.8f;
+            CompatibilityInfo.setOverrideInvertedScale(scale);
+            // Send activity level config change.
+            newConfig.seq++;
+            newConfig.smallestScreenWidthDp++;
+            transaction = newTransaction(activityThread, activity.getActivityToken());
+            transaction.addCallback(ActivityConfigurationChangeItem.obtain(
+                    new Configuration(newConfig)));
+            appThread.scheduleTransaction(transaction);
+            InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+            assertScreenScale(scale, activity, originalActivityConfig, originalActivityMetrics);
+        } finally {
+            CompatibilityInfo.setOverrideInvertedScale(originalScale);
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                    () -> restoreConfig(activityThread, originalAppConfig));
+        }
+        assertScreenScale(originalScale, app, originalAppConfig, originalAppMetrics);
+    }
+
+    private static void assertScreenScale(float scale, Context context,
+            Configuration origConfig, DisplayMetrics origMetrics) {
+        final int expectedDpi = (int) (origConfig.densityDpi * scale + .5f);
+        final float expectedDensity = origMetrics.density * scale;
+        final int expectedWidthPixels = (int) (origMetrics.widthPixels * scale + .5f);
+        final int expectedHeightPixels = (int) (origMetrics.heightPixels * scale + .5f);
+        final Configuration expectedConfig = new Configuration(origConfig);
+        CompatibilityInfo.scaleConfiguration(scale, expectedConfig);
+        final Rect expectedBounds = expectedConfig.windowConfiguration.getBounds();
+        final Rect expectedAppBounds = expectedConfig.windowConfiguration.getAppBounds();
+        final Rect expectedMaxBounds = expectedConfig.windowConfiguration.getMaxBounds();
+
+        final Configuration currentConfig = context.getResources().getConfiguration();
+        final DisplayMetrics currentMetrics = context.getResources().getDisplayMetrics();
+        assertEquals(expectedDpi, currentConfig.densityDpi);
+        assertEquals(expectedDpi, currentMetrics.densityDpi);
+        assertEquals(expectedDensity, currentMetrics.density, 0.001f);
+        assertEquals(expectedWidthPixels, currentMetrics.widthPixels);
+        assertEquals(expectedHeightPixels, currentMetrics.heightPixels);
+        assertEquals(expectedBounds, currentConfig.windowConfiguration.getBounds());
+        assertEquals(expectedAppBounds, currentConfig.windowConfiguration.getAppBounds());
+        assertEquals(expectedMaxBounds, currentConfig.windowConfiguration.getMaxBounds());
+    }
+
+    @Test
     public void testHandleActivityConfigurationChanged() {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
 
@@ -459,19 +540,17 @@
             } finally {
                 // Make sure to reset the process config to prevent side effects to other
                 // tests.
-                Configuration activityThreadConfig = activityThread.getConfiguration();
-                activityThreadConfig.seq = originalAppConfig.seq - 1;
-
-                Configuration resourceManagerConfig = ResourcesManager.getInstance()
-                        .getConfiguration();
-                resourceManagerConfig.seq = originalAppConfig.seq - 1;
-
-                activityThread.updatePendingConfiguration(originalAppConfig);
-                activityThread.handleConfigurationChanged(originalAppConfig);
+                restoreConfig(activityThread, originalAppConfig);
             }
         });
     }
 
+    private static void restoreConfig(ActivityThread thread, Configuration originalConfig) {
+        thread.getConfiguration().seq = originalConfig.seq - 1;
+        ResourcesManager.getInstance().getConfiguration().seq = originalConfig.seq - 1;
+        thread.handleConfigurationChanged(originalConfig);
+    }
+
     @Test
     public void testActivityOrientationChanged_DoesntOverrideVirtualDisplayOrientation() {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/core/tests/coretests/src/android/ddm/DdmHandleViewDebugTest.java b/core/tests/coretests/src/android/ddm/DdmHandleViewDebugTest.java
new file mode 100644
index 0000000..7248983
--- /dev/null
+++ b/core/tests/coretests/src/android/ddm/DdmHandleViewDebugTest.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.ddm;
+
+import static android.ddm.DdmHandleViewDebug.deserializeMethodParameters;
+import static android.ddm.DdmHandleViewDebug.serializeReturnValue;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.ddm.DdmHandleViewDebug.ViewMethodInvocationSerializationException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class DdmHandleViewDebugTest {
+    // true
+    private static final byte[] SERIALIZED_BOOLEAN_TRUE = {0x00, 0x5A, 1};
+
+    @Test
+    public void serializeReturnValue_booleanTrue() throws Exception {
+        assertArrayEquals(SERIALIZED_BOOLEAN_TRUE, serializeReturnValue(boolean.class, true));
+    }
+
+    @Test
+    public void deserializeMethodParameters_booleanTrue() throws Exception {
+        expectDeserializedArgument(boolean.class, true, SERIALIZED_BOOLEAN_TRUE);
+    }
+
+    // false
+    private static final byte[] SERIALIZED_BOOLEAN_FALSE = {0x00, 0x5A, 0};
+
+    @Test
+    public void serializeReturnValue_booleanFalse() throws Exception {
+        assertArrayEquals(SERIALIZED_BOOLEAN_FALSE, serializeReturnValue(boolean.class, false));
+    }
+
+    @Test
+    public void deserializeMethodParameters_booleanFalse() throws Exception {
+        expectDeserializedArgument(boolean.class, false, SERIALIZED_BOOLEAN_FALSE);
+    }
+
+    // (byte) 42
+    private static final byte[] SERIALIZED_BYTE = {0x00, 0x42, 42};
+
+    @Test
+    public void serializeReturnValue_byte() throws Exception {
+        assertArrayEquals(SERIALIZED_BYTE, serializeReturnValue(byte.class, (byte) 42));
+    }
+
+    @Test
+    public void deserializeMethodParameters_byte() throws Exception {
+        expectDeserializedArgument(byte.class, (byte) 42, SERIALIZED_BYTE);
+    }
+
+    // '\u1122'
+    private static final byte[] SERIALIZED_CHAR = {0x00, 0x43, 0x11, 0x22};
+
+    @Test
+    public void serializeReturnValue_char() throws Exception {
+        assertArrayEquals(SERIALIZED_CHAR, serializeReturnValue(char.class, '\u1122'));
+    }
+
+    @Test
+    public void deserializeMethodParameters_char() throws Exception {
+        expectDeserializedArgument(char.class, '\u1122', SERIALIZED_CHAR);
+    }
+
+    // (short) 0x1011
+    private static final byte[] SERIALIZED_SHORT = {0x00, 0x53, 0x10, 0x11};
+
+    @Test
+    public void serializeReturnValue_short() throws Exception {
+        assertArrayEquals(SERIALIZED_SHORT,
+                serializeReturnValue(short.class, (short) 0x1011));
+    }
+
+    @Test
+    public void deserializeMethodParameters_short() throws Exception {
+        expectDeserializedArgument(short.class, (short) 0x1011, SERIALIZED_SHORT);
+    }
+
+    // 0x11223344
+    private static final byte[] SERIALIZED_INT = {0x00, 0x49, 0x11, 0x22, 0x33, 0x44};
+
+    @Test
+    public void serializeReturnValue_int() throws Exception {
+        assertArrayEquals(SERIALIZED_INT,
+                serializeReturnValue(int.class, 0x11223344));
+    }
+
+    @Test
+    public void deserializeMethodParameters_int() throws Exception {
+        expectDeserializedArgument(int.class, 0x11223344, SERIALIZED_INT);
+    }
+
+    // 0x0011223344556677L
+    private static final byte[] SERIALIZED_LONG =
+            {0x00, 0x4a, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+
+    @Test
+    public void serializeReturnValue_long() throws Exception {
+        assertArrayEquals(SERIALIZED_LONG,
+                serializeReturnValue(long.class, 0x0011223344556677L));
+    }
+
+    @Test
+    public void deserializeMethodParameters_long() throws Exception {
+        expectDeserializedArgument(long.class, 0x0011223344556677L, SERIALIZED_LONG);
+    }
+
+    // 3.141d
+    private static final byte[] SERIALIZED_DOUBLE =
+            {0x00, 0x44, (byte) 0x40, (byte) 0x09, (byte) 0x20, (byte) 0xc4, (byte) 0x9b,
+                    (byte) 0xa5, (byte) 0xe3, (byte) 0x54};
+
+    @Test
+    public void serializeReturnValue_double() throws Exception {
+        assertArrayEquals(
+                SERIALIZED_DOUBLE,
+                serializeReturnValue(double.class, 3.141d));
+    }
+
+    @Test
+    public void deserializeMethodParameters_double() throws Exception {
+        expectDeserializedArgument(double.class, 3.141d, SERIALIZED_DOUBLE);
+    }
+
+    // 3.141f
+    private static final byte[] SERIALIZED_FLOAT =
+            {0x00, 0x46, (byte) 0x40, (byte) 0x49, (byte) 0x06, (byte) 0x25};
+
+    @Test
+    public void serializeReturnValue_float() throws Exception {
+        assertArrayEquals(SERIALIZED_FLOAT,
+                serializeReturnValue(float.class, 3.141f));
+    }
+
+    @Test
+    public void deserializeMethodParameters_float() throws Exception {
+        expectDeserializedArgument(float.class, 3.141f, SERIALIZED_FLOAT);
+    }
+
+    // "foo"
+    private static final byte[] SERIALIZED_ASCII_STRING = {0x00, 0x52, 0, 3, 0x66, 0x6f, 0x6f};
+
+    @Test
+    public void serializeReturnValue_asciiString() throws Exception {
+        assertArrayEquals(SERIALIZED_ASCII_STRING,
+                serializeReturnValue(String.class, "foo"));
+    }
+
+    @Test
+    public void deserializeMethodParameters_asciiString() throws Exception {
+        expectDeserializedArgument(String.class, "foo", SERIALIZED_ASCII_STRING);
+    }
+
+    // "\u1122"
+    private static final byte[] SERIALIZED_NON_ASCII_STRING =
+            {0x00, 0x52, 0, 3, (byte) 0xe1, (byte) 0x84, (byte) 0xa2};
+
+    @Test
+    public void serializeReturnValue_nonAsciiString_encodesAsUtf8() throws Exception {
+        assertArrayEquals(SERIALIZED_NON_ASCII_STRING,
+                serializeReturnValue(String.class, "\u1122"));
+    }
+
+    @Test
+    public void deserializeMethodParameters_decodesFromUtf8() throws Exception {
+        expectDeserializedArgument(String.class, "\u1122", SERIALIZED_NON_ASCII_STRING);
+    }
+
+    // ""
+    private static final byte[] SERIALIZED_EMPTY_STRING = {0x00, 0x52, 0, 0};
+
+    @Test
+    public void serializeReturnValue_emptyString() throws Exception {
+        assertArrayEquals(SERIALIZED_EMPTY_STRING, serializeReturnValue(String.class, ""));
+    }
+
+    @Test
+    public void deserializeMethodParameters_emptyString() throws Exception {
+        expectDeserializedArgument(String.class, "", SERIALIZED_EMPTY_STRING);
+    }
+
+    @Test
+    public void serializeReturnValue_nullString_encodesAsEmptyString() throws Exception {
+        assertArrayEquals(new byte[]{0x00, 0x52, 0, 0}, serializeReturnValue(String.class, null));
+    }
+
+    // Illegal - string length exceeding actual bytes
+    private static final byte[] SERIALIZED_INVALID_STRING =
+            {0x00, 0x52, 0, 3, 0x66};
+
+    @Test
+    public void deserializeMethodParameters_stringPayloadMissing_throws() throws Exception {
+        Object[] args = new Object[1];
+        Class<?>[] argTypes = new Class<?>[1];
+        assertThrows(BufferUnderflowException.class,
+                () -> deserializeMethodParameters(args, argTypes,
+                        ByteBuffer.wrap(SERIALIZED_INVALID_STRING)));
+    }
+
+    @Test
+    public void serializeAndDeserialize_handlesStringsUpTo64k() throws Exception {
+        char[] chars = new char[65535];
+        Arrays.fill(chars, 'a');
+        String original = new String(chars);
+        byte[] serialized = serializeReturnValue(String.class, original);
+
+        // 2 bytes for the R signature char, 2 bytes char string byte count, 2^16-1 bytes ASCII
+        // payload
+        assertEquals(2 + 2 + 65535, serialized.length);
+
+        // length is unsigned short
+        assertArrayEquals(new byte[]{0x00, 0x52, (byte) 0xff, (byte) 0xff},
+                Arrays.copyOfRange(serialized, 0, 4));
+
+        // length of string must be interpreted as unsigned short, returning original content
+        expectDeserializedArgument(String.class, original, serialized);
+    }
+
+    private static final byte[] SERIALIZED_VOID = {0x00, 0x56};
+
+    @Test
+    public void serializeReturnValue_void() throws Exception {
+        assertArrayEquals(SERIALIZED_VOID, serializeReturnValue(void.class, null));
+    }
+
+    @Test
+    public void deserializeMethodParameters_void_throws() throws Exception {
+        Object[] args = new Object[1];
+        Class<?>[] argTypes = new Class<?>[1];
+        assertThrows(ViewMethodInvocationSerializationException.class,
+                () -> deserializeMethodParameters(args, argTypes,
+                        ByteBuffer.wrap(SERIALIZED_VOID)));
+    }
+
+    // new byte[]{}
+    private static final byte[] SERIALIZED_EMPTY_BYTE_ARRAY = {0x00, 0x5b, 0x00, 0x42, 0, 0, 0, 0};
+
+    @Test
+    public void serializeReturnValue_emptyByteArray() throws Exception {
+        assertArrayEquals(SERIALIZED_EMPTY_BYTE_ARRAY,
+                serializeReturnValue(byte[].class, new byte[]{}));
+    }
+
+    @Test
+    public void deserializeMethodParameters_emptyByteArray() throws Exception {
+        expectDeserializedArgument(byte[].class, new byte[]{}, SERIALIZED_EMPTY_BYTE_ARRAY);
+    }
+
+    // new byte[]{0, 42}
+    private static final byte[] SERIALIZED_SIMPLE_BYTE_ARRAY =
+            {0x00, 0x5b, 0x00, 0x42, 0, 0, 0, 2, 0, 42};
+
+    @Test
+    public void serializeReturnValue_byteArray() throws Exception {
+        assertArrayEquals(SERIALIZED_SIMPLE_BYTE_ARRAY,
+                serializeReturnValue(byte[].class, new byte[]{0, 42}));
+    }
+
+    @Test
+    public void deserializeMethodParameters_byteArray() throws Exception {
+        expectDeserializedArgument(byte[].class, new byte[]{0, 42}, SERIALIZED_SIMPLE_BYTE_ARRAY);
+    }
+
+    @Test
+    public void serializeReturnValue_largeByteArray_encodesSizeCorrectly() throws Exception {
+        byte[] result = serializeReturnValue(byte[].class, new byte[0x012233]);
+        // 2 bytes for the each [Z signature char, 4 bytes int array length, 0x012233 bytes payload
+        assertEquals(2 + 2 + 4 + 74291, result.length);
+
+        assertArrayEquals(new byte[]{0x00, 0x5b, 0x00, 0x42, 0x00, 0x01, 0x22, 0x33},
+                Arrays.copyOfRange(result, 0, 8));
+    }
+
+    // Illegal - declared size exceeds remaining buffer length
+    private static final byte[] SERIALIZED_INVALID_BYTE_ARRAY =
+            {0x00, 0x5b, 0x00, 0x42, 0, 0, 0, 3, 0, 42};
+
+    @Test
+    public void deserializeMethodParameters_sizeExceedsBuffer_throws() throws Exception {
+        Object[] args = new Object[1];
+        Class<?>[] argTypes = new Class<?>[1];
+        assertThrows(BufferUnderflowException.class,
+                () -> deserializeMethodParameters(args, argTypes,
+                        ByteBuffer.wrap(SERIALIZED_INVALID_BYTE_ARRAY)));
+    }
+
+    // new int[]{}
+    private static final byte[] SERIALIZED_EMPTY_INT_ARRAY = {0x00, 0x5b, 0x00, 0x49, 0, 0, 0, 0};
+
+    @Test
+    public void serializeReturnValue_nonByteArrayType_throws() throws Exception {
+        assertThrows(ViewMethodInvocationSerializationException.class,
+                () -> serializeReturnValue(int[].class, 42));
+    }
+
+    @Test
+    public void deserializeMethodParameters_nonByteArrayType_throws() throws Exception {
+        Object[] args = new Object[1];
+        Class<?>[] argTypes = new Class<?>[1];
+        assertThrows(ViewMethodInvocationSerializationException.class,
+                () -> deserializeMethodParameters(args, argTypes,
+                        ByteBuffer.wrap(SERIALIZED_EMPTY_INT_ARRAY)));
+    }
+
+    // new byte[]{0, 42}
+    private static final byte[] SERIALIZED_MULTIPLE_PARAMETERS =
+            {0x00, 0x42, 42, 0x00, 0x5A, 1};
+
+    @Test
+    public void deserializeMethodParameters_multipleParameters() throws Exception {
+        expectDeserializedArguments(new Class[]{byte.class, boolean.class},
+                new Object[]{(byte) 42, true}, SERIALIZED_MULTIPLE_PARAMETERS);
+    }
+
+    // Illegal - type 'X'
+    private static final byte[] SERIALIZED_INVALID_UNKNOWN_TYPE = {0x00, 0x58};
+
+    @Test
+    public void deserializeMethodParameters_unknownType_throws() throws Exception {
+        Object[] args = new Object[1];
+        Class<?>[] argTypes = new Class<?>[1];
+        assertThrows(ViewMethodInvocationSerializationException.class,
+                () -> deserializeMethodParameters(args, argTypes,
+                        ByteBuffer.wrap(SERIALIZED_INVALID_UNKNOWN_TYPE)));
+    }
+
+    @Test
+    public void deserializeMethodParameters_noArgumentsEmptyPacket_isNoop() throws Exception {
+        Object[] args = new Object[0];
+        Class<?>[] argTypes = new Class<?>[0];
+        deserializeMethodParameters(args, argTypes, ByteBuffer.wrap(new byte[0]));
+    }
+
+    @Test
+    public void deserializeMethodParameters_withArgumentsEmptyPacket_throws() throws Exception {
+        Object[] args = new Object[1];
+        Class<?>[] argTypes = new Class<?>[1];
+        assertThrows(BufferUnderflowException.class,
+                () -> deserializeMethodParameters(args, argTypes, ByteBuffer.wrap(new byte[0])));
+    }
+
+    private static void expectDeserializedArgument(Class<?> expectedType, Object expectedValue,
+            byte[] argumentBuffer) throws Exception {
+        expectDeserializedArguments(new Class[]{expectedType}, new Object[]{expectedValue},
+                argumentBuffer);
+    }
+
+    private static void expectDeserializedArguments(Class<?>[] expectedTypes,
+            Object[] expectedValues, byte[] argumentBuffer) throws Exception {
+        final int argCount = expectedTypes.length;
+        assertEquals("test helper not used correctly", argCount, expectedValues.length);
+        Object[] actualArgs = new Object[argCount];
+        Class<?>[] actualArgTypes = new Class<?>[argCount];
+
+        ByteBuffer buffer = ByteBuffer.wrap(argumentBuffer);
+        deserializeMethodParameters(actualArgs, actualArgTypes, buffer);
+
+        for (int i = 0; i < argCount; i++) {
+            String context = "argument " + i;
+            assertEquals(context, expectedTypes[i], actualArgTypes[i]);
+            if (byte[].class.equals(expectedTypes[i])) {
+                assertArrayEquals((byte[]) expectedValues[i], (byte[]) actualArgs[i]);
+            } else {
+                assertEquals(expectedValues[i], actualArgs[i]);
+            }
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/ddm/OWNERS b/core/tests/coretests/src/android/ddm/OWNERS
new file mode 100644
index 0000000..c8be191
--- /dev/null
+++ b/core/tests/coretests/src/android/ddm/OWNERS
@@ -0,0 +1 @@
+michschn@google.com
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt b/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
new file mode 100644
index 0000000..e3b3ea7
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.input
+
+import android.hardware.BatteryState
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.test.TestLooper
+import android.platform.test.annotations.Presubmit
+import com.android.server.testutils.any
+import java.util.concurrent.Executor
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+import kotlin.test.fail
+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.anyInt
+import org.mockito.Mockito.doAnswer
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoJUnitRunner
+
+/**
+ * Tests for [InputManager.InputDeviceBatteryListener].
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:InputDeviceBatteryListenerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner::class)
+class InputDeviceBatteryListenerTest {
+    @get:Rule
+    val rule = MockitoJUnit.rule()!!
+
+    private lateinit var testLooper: TestLooper
+    private var registeredListener: IInputDeviceBatteryListener? = null
+    private val monitoredDevices = mutableListOf<Int>()
+    private lateinit var executor: Executor
+    private lateinit var inputManager: InputManager
+
+    @Mock
+    private lateinit var iInputManagerMock: IInputManager
+
+    @Before
+    fun setUp() {
+        testLooper = TestLooper()
+        executor = HandlerExecutor(Handler(testLooper.looper))
+        registeredListener = null
+        monitoredDevices.clear()
+        inputManager = InputManager.resetInstance(iInputManagerMock)
+
+        // Handle battery listener registration.
+        doAnswer {
+            val deviceId = it.getArgument(0) as Int
+            val listener = it.getArgument(1) as IInputDeviceBatteryListener
+            if (registeredListener != null &&
+                    registeredListener!!.asBinder() != listener.asBinder()) {
+                // There can only be one registered battery listener per process.
+                fail("Trying to register a new listener when one already exists")
+            }
+            if (monitoredDevices.contains(deviceId)) {
+                fail("Trying to start monitoring a device that was already being monitored")
+            }
+            monitoredDevices.add(deviceId)
+            registeredListener = listener
+            null
+        }.`when`(iInputManagerMock).registerBatteryListener(anyInt(), any())
+
+        // Handle battery listener being unregistered.
+        doAnswer {
+            val deviceId = it.getArgument(0) as Int
+            val listener = it.getArgument(1) as IInputDeviceBatteryListener
+            if (registeredListener == null ||
+                    registeredListener!!.asBinder() != listener.asBinder()) {
+                fail("Trying to unregister a listener that is not registered")
+            }
+            if (!monitoredDevices.remove(deviceId)) {
+                fail("Trying to stop monitoring a device that is not being monitored")
+            }
+            if (monitoredDevices.isEmpty()) {
+                registeredListener = null
+            }
+        }.`when`(iInputManagerMock).unregisterBatteryListener(anyInt(), any())
+    }
+
+    @After
+    fun tearDown() {
+        InputManager.clearInstance()
+    }
+
+    private fun notifyBatteryStateChanged(
+        deviceId: Int,
+        isPresent: Boolean = true,
+        status: Int = BatteryState.STATUS_FULL,
+        capacity: Float = 1.0f,
+        eventTime: Long = 12345L
+    ) {
+        registeredListener!!.onBatteryStateChanged(deviceId, isPresent, status, capacity, eventTime)
+    }
+
+    @Test
+    fun testListenerIsNotifiedCorrectly() {
+        var callbackCount = 0
+
+        // Add a battery listener to monitor battery changes.
+        inputManager.addInputDeviceBatteryListener(1 /*deviceId*/, executor) {
+                deviceId: Int, eventTime: Long, batteryState: BatteryState ->
+            callbackCount++
+            assertEquals(1, deviceId)
+            assertEquals(true, batteryState.isPresent)
+            assertEquals(BatteryState.STATUS_DISCHARGING, batteryState.status)
+            assertEquals(0.5f, batteryState.capacity)
+            assertEquals(8675309L, eventTime)
+        }
+
+        // Adding the listener should register the callback with InputManagerService.
+        assertNotNull(registeredListener)
+        assertTrue(monitoredDevices.contains(1))
+
+        // Notifying battery change for a different device should not trigger the listener.
+        notifyBatteryStateChanged(deviceId = 2)
+        testLooper.dispatchAll()
+        assertEquals(0, callbackCount)
+
+        // Notifying battery change for the registered device will notify the listener.
+        notifyBatteryStateChanged(1 /*deviceId*/, true /*isPresent*/,
+            BatteryState.STATUS_DISCHARGING, 0.5f /*capacity*/, 8675309L /*eventTime*/)
+        testLooper.dispatchNext()
+        assertEquals(1, callbackCount)
+    }
+
+    @Test
+    fun testMultipleListeners() {
+        // Set up two callbacks.
+        var callbackCount1 = 0
+        var callbackCount2 = 0
+        val callback1 = InputManager.InputDeviceBatteryListener { _, _, _ -> callbackCount1++ }
+        val callback2 = InputManager.InputDeviceBatteryListener { _, _, _ -> callbackCount2++ }
+
+        // Monitor battery changes for three devices. The first callback monitors devices 1 and 3,
+        // while the second callback monitors devices 2 and 3.
+        inputManager.addInputDeviceBatteryListener(1 /*deviceId*/, executor, callback1)
+        assertEquals(1, monitoredDevices.size)
+        inputManager.addInputDeviceBatteryListener(2 /*deviceId*/, executor, callback2)
+        assertEquals(2, monitoredDevices.size)
+        inputManager.addInputDeviceBatteryListener(3 /*deviceId*/, executor, callback1)
+        assertEquals(3, monitoredDevices.size)
+        inputManager.addInputDeviceBatteryListener(3 /*deviceId*/, executor, callback2)
+        assertEquals(3, monitoredDevices.size)
+
+        // Notifying battery change for each of the devices should trigger the registered callbacks.
+        notifyBatteryStateChanged(deviceId = 1)
+        testLooper.dispatchNext()
+        assertEquals(1, callbackCount1)
+        assertEquals(0, callbackCount2)
+
+        notifyBatteryStateChanged(deviceId = 2)
+        testLooper.dispatchNext()
+        assertEquals(1, callbackCount1)
+        assertEquals(1, callbackCount2)
+
+        notifyBatteryStateChanged(deviceId = 3)
+        testLooper.dispatchNext()
+        testLooper.dispatchNext()
+        assertEquals(2, callbackCount1)
+        assertEquals(2, callbackCount2)
+
+        // Stop monitoring devices 1 and 2.
+        inputManager.removeInputDeviceBatteryListener(1 /*deviceId*/, callback1)
+        assertEquals(2, monitoredDevices.size)
+        inputManager.removeInputDeviceBatteryListener(2 /*deviceId*/, callback2)
+        assertEquals(1, monitoredDevices.size)
+
+        // Ensure device 3 continues to be monitored.
+        notifyBatteryStateChanged(deviceId = 3)
+        testLooper.dispatchNext()
+        testLooper.dispatchNext()
+        assertEquals(3, callbackCount1)
+        assertEquals(3, callbackCount2)
+
+        // Stop monitoring all devices.
+        inputManager.removeInputDeviceBatteryListener(3 /*deviceId*/, callback1)
+        assertEquals(1, monitoredDevices.size)
+        inputManager.removeInputDeviceBatteryListener(3 /*deviceId*/, callback2)
+        assertEquals(0, monitoredDevices.size)
+    }
+
+    @Test
+    fun testAdditionalListenersNotifiedImmediately() {
+        var callbackCount1 = 0
+        var callbackCount2 = 0
+        val callback1 = InputManager.InputDeviceBatteryListener { _, _, _ -> callbackCount1++ }
+        val callback2 = InputManager.InputDeviceBatteryListener { _, _, _ -> callbackCount2++ }
+
+        // Add a battery listener and send the latest battery state.
+        inputManager.addInputDeviceBatteryListener(1 /*deviceId*/, executor, callback1)
+        assertEquals(1, monitoredDevices.size)
+        notifyBatteryStateChanged(deviceId = 1)
+        testLooper.dispatchNext()
+        assertEquals(1, callbackCount1)
+
+        // Add a second listener for the same device that already has the latest battery state.
+        inputManager.addInputDeviceBatteryListener(1 /*deviceId*/, executor, callback2)
+        assertEquals(1, monitoredDevices.size)
+
+        // Ensure that this listener is notified immediately.
+        testLooper.dispatchNext()
+        assertEquals(1, callbackCount2)
+    }
+}
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
index e13a332..3ecc7ff 100644
--- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
@@ -110,11 +110,10 @@
     }
 
     private InputDevice createInputDevice(int id) {
-        return new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name",
-                0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
-                0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */,
-                InputDeviceCountryCode.INVALID, false /* hasVibrator */, false /* hasMicrophone */,
-                false /* hasButtonUnderpad */, false /* hasSensor */, false /* hasBattery */);
+        return new InputDevice.Builder()
+                .setId(id)
+                .setName("Test Device " + id)
+                .build();
     }
 
     private void mockLights(Light[] lights) throws Exception {
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
index 54ee434..6cf2314 100644
--- a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
@@ -35,7 +35,6 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
-import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.view.InputDevice;
 
@@ -73,10 +72,7 @@
 
     @Rule public final MockitoRule mockito = MockitoJUnit.rule();
 
-    private TestLooper mTestLooper;
-    private ContextWrapper mContextSpy;
     private InputManager mInputManager;
-    private InputDeviceSensorManager mSensorManager;
     private IInputSensorEventListener mIInputSensorEventListener;
     private final Object mLock = new Object();
 
@@ -84,11 +80,10 @@
 
     @Before
     public void setUp() throws Exception {
-        mTestLooper = new TestLooper();
-        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+        final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
         InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
 
-        when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
+        when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
 
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID});
 
@@ -104,7 +99,7 @@
 
         when(mIInputManagerMock.registerSensorListener(any())).thenReturn(true);
 
-        mInputManager = mContextSpy.getSystemService(InputManager.class);
+        mInputManager = context.getSystemService(InputManager.class);
     }
 
     @After
@@ -145,13 +140,11 @@
     }
 
     private InputDevice createInputDeviceWithSensor(int id) {
-        InputDevice d = new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name",
-                0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
-                0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */,
-                InputDeviceCountryCode.INVALID, false /* hasVibrator */, false /* hasMicrophone */,
-                false /* hasButtonUnderpad */, true /* hasSensor */, false /* hasBattery */);
-        assertTrue(d.hasSensor());
-        return d;
+        return new InputDevice.Builder()
+                .setId(id)
+                .setName("Test Device " + id)
+                .setHasSensor(true)
+                .build();
     }
 
     private InputSensorInfo createInputSensorInfo(int id, int type) {
@@ -164,8 +157,8 @@
     }
 
     private InputDevice getSensorDevice(int[] deviceIds) {
-        for (int i = 0; i < deviceIds.length; i++) {
-            InputDevice device = mInputManager.getInputDevice(deviceIds[i]);
+        for (int deviceId : deviceIds) {
+            InputDevice device = mInputManager.getInputDevice(deviceId);
             if (device.hasSensor()) {
                 return device;
             }
@@ -176,7 +169,7 @@
     @Test
     public void getInputDeviceSensors_withExpectedType() throws Exception {
         InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
-        assertTrue(device != null);
+        assertNotNull(device);
 
         SensorManager sensorManager = device.getSensorManager();
         List<Sensor> accelList = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
@@ -197,7 +190,7 @@
     public void getInputDeviceSensors_withUnexpectedType() throws Exception {
         InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
 
-        assertTrue(device != null);
+        assertNotNull(device);
         SensorManager sensorManager = device.getSensorManager();
 
         List<Sensor> gameRotationList = sensorManager.getSensorList(
@@ -213,7 +206,7 @@
     @Test
     public void testInputDeviceSensorListener() throws Exception {
         InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
-        assertTrue(device != null);
+        assertNotNull(device);
 
         SensorManager sensorManager = device.getSensorManager();
         Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
new file mode 100644
index 0000000..42629ba
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConditionTest {
+    private static final String CLASS = "android.service.notification.Condition";
+
+    @Test
+    public void testLongFields_inConstructors() {
+        String longString = Strings.repeat("A", 65536);
+        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+        // Confirm strings are truncated via short constructor
+        Condition cond1 = new Condition(longUri, longString, Condition.STATE_TRUE);
+
+        assertEquals(Condition.MAX_STRING_LENGTH, cond1.id.toString().length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond1.summary.length());
+
+        // Confirm strings are truncated via long constructor
+        Condition cond2 = new Condition(longUri, longString, longString, longString,
+                -1, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.id.toString().length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.summary.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.line1.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, cond2.line2.length());
+    }
+
+    @Test
+    public void testLongFields_viaParcel() {
+        // Set fields via reflection to force them to be long, then parcel and unparcel to make sure
+        // it gets truncated upon unparcelling.
+        Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder",
+                Condition.STATE_TRUE);
+
+        try {
+            String longString = Strings.repeat("A", 65536);
+            Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+            Field id = Class.forName(CLASS).getDeclaredField("id");
+            id.setAccessible(true);
+            id.set(cond, longUri);
+            Field summary = Class.forName(CLASS).getDeclaredField("summary");
+            summary.setAccessible(true);
+            summary.set(cond, longString);
+            Field line1 = Class.forName(CLASS).getDeclaredField("line1");
+            line1.setAccessible(true);
+            line1.set(cond, longString);
+            Field line2 = Class.forName(CLASS).getDeclaredField("line2");
+            line2.setAccessible(true);
+            line2.set(cond, longString);
+        } catch (NoSuchFieldException e) {
+            fail(e.toString());
+        } catch (ClassNotFoundException e) {
+            fail(e.toString());
+        } catch (IllegalAccessException e) {
+            fail(e.toString());
+        }
+
+        Parcel parcel = Parcel.obtain();
+        cond.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        Condition fromParcel = new Condition(parcel);
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.id.toString().length());
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.summary.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line1.length());
+        assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line2.length());
+    }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java b/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java
new file mode 100644
index 0000000..2bb5abe
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/BaseInputConnectionTest.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.inputmethod;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.SuggestionSpan;
+import android.view.View;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BaseInputConnectionTest {
+    private static final int[] CURSOR_CAPS_MODES =
+            new int[] {
+                InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
+                InputType.TYPE_TEXT_FLAG_CAP_WORDS,
+                InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
+            };
+
+    private BaseInputConnection mBaseInputConnection;
+    private Editable mEditable;
+    private View mMockView;
+
+    @Before
+    public void setUp() throws Exception {
+        mMockView = new View(InstrumentationRegistry.getInstrumentation().getContext());
+        mBaseInputConnection = new BaseInputConnection(mMockView, /*fullEditor=*/ true);
+        mEditable = mBaseInputConnection.getEditable();
+        verifyContent("", 0, 0, -1, -1);
+    }
+
+    @Test
+    public void testCommitText_toEditorWithoutSelectionAndComposing() {
+        // before commit: "|"
+        // after commit: "text1|"
+        assertThat(mBaseInputConnection.commitText("text1", 1)).isTrue();
+        verifyContent("text1", 5, 5, -1, -1);
+
+        // before commit: "text1|"
+        // after commit: "text1text2|"
+        assertThat(mBaseInputConnection.commitText("text2", "text1".length())).isTrue();
+        verifyContent("text1text2", 10, 10, -1, -1);
+
+        // before commit: "text1text2|"
+        // after commit: "text1text2text3|"
+        assertThat(mBaseInputConnection.commitText("text3", 100)).isTrue();
+        verifyContent("text1text2text3", 15, 15, -1, -1);
+
+        // before commit: "text1text2text3|"
+        // after commit: "text1text2text3text4|"
+        // BUG(b/21476564): this behavior is inconsistent with API description.
+        assertThat(mBaseInputConnection.commitText("text4", 0)).isTrue();
+        verifyContent("text1text2text3text4", 20, 20, -1, -1);
+
+        // before commit: "text1text2text3text4|"
+        // after commit: "text1text2text3text|4text5"
+        assertThat(mBaseInputConnection.commitText("text5", -1)).isTrue();
+        verifyContent("text1text2text3text4text5", 19, 19, -1, -1);
+
+        // before commit: "text1text2text3text|4text5"
+        // after commit: "text1text2text3te|xttext64text5"
+        assertThat(mBaseInputConnection.commitText("text6", -2)).isTrue();
+        verifyContent("text1text2text3texttext64text5", 17, 17, -1, -1);
+
+        // before commit: "text1text2text3te|xttext64text5"
+        // after commit: "|text1text2text3tetext7xttext64text5"
+        assertThat(mBaseInputConnection.commitText("text7", -100)).isTrue();
+        verifyContent("text1text2text3tetext7xttext64text5", 0, 0, -1, -1);
+    }
+
+    @Test
+    public void testCommitText_toEditorWithSelection() {
+        // before commit: "123|456|789"
+        // before commit: "123text|789"
+        prepareContent("123456789", 3, 6, -1, -1);
+        assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+        verifyContent("123text789", 7, 7, -1, -1);
+
+        // before commit: "|123|"
+        // before commit: "|text"
+        prepareContent("123", 0, 3, -1, -1);
+        assertThat(mBaseInputConnection.commitText("text", 0)).isTrue();
+        verifyContent("text", 0, 0, -1, -1);
+    }
+
+    @Test
+    public void testCommitText_toEditorWithComposing() {
+        // before commit: "123456|789"
+        //                    ---
+        // before commit: "123text|789"
+        prepareContent("123456789", 6, 6, 3, 6);
+        assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+        verifyContent("123text789", 7, 7, -1, -1);
+
+        // before commit: "123456789|"
+        //                    ---
+        // before commit: "123text|789"
+        prepareContent("123456789", 6, 6, 3, 6);
+        assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+        verifyContent("123text789", 7, 7, -1, -1);
+
+        // before commit: "|123456789|"
+        //                     ---
+        // before commit: "123text|789"
+        prepareContent("123456789", 0, 9, 3, 6);
+        assertThat(mBaseInputConnection.commitText("text", 1)).isTrue();
+        verifyContent("123text789", 7, 7, -1, -1);
+    }
+
+    @Test
+    public void deleteSurroundingText_fromEditorWithoutSelectionAndComposing() {
+        // before delete: "123456789|"
+        // after delete: "123456|"
+        prepareContent("123456789", 9, 9, -1, -1);
+        assertThat(mBaseInputConnection.deleteSurroundingText(3, 0)).isTrue();
+        verifyContent("123456", 6, 6, -1, -1);
+
+        // before delete: "123456|"
+        // after delete: "|"
+        assertThat(mBaseInputConnection.deleteSurroundingText(100, 0)).isTrue();
+        verifyContent("", 0, 0, -1, -1);
+
+        // before commit: "|123456789"
+        // after delete: "|456789"
+        prepareContent("123456789", 0, 0, -1, -1);
+        assertThat(mBaseInputConnection.deleteSurroundingText(0, 3)).isTrue();
+        verifyContent("456789", 0, 0, -1, -1);
+
+        // before delete: "|123456789"
+        // after delete: "|"
+        assertThat(mBaseInputConnection.deleteSurroundingText(0, 100)).isTrue();
+        verifyContent("", 0, 0, -1, -1);
+
+        // before delete: "123|456789"
+        // after delete: "1|789"
+        prepareContent("123456789", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.deleteSurroundingText(2, 3)).isTrue();
+        verifyContent("1789", 1, 1, -1, -1);
+    }
+
+    @Test
+    public void deleteSurroundingText_fromEditorSelectionOrComposing() {
+        // before delete: "123|456|789"
+        // before delete: "12|456|9"
+        prepareContent("123456789", 3, 6, -1, -1);
+        assertThat(mBaseInputConnection.deleteSurroundingText(1, 2)).isTrue();
+        verifyContent("124569", 2, 5, -1, -1);
+
+        // before delete: "12|456|9"
+        // before delete: "|456|"
+        assertThat(mBaseInputConnection.deleteSurroundingText(100, 100)).isTrue();
+        verifyContent("456", 0, 3, -1, -1);
+
+        // before commit: "123456|789"
+        //                    ---
+        // before commit: "1[456]|89"
+        prepareContent("123456789", 6, 6, 3, 6);
+        assertThat(mBaseInputConnection.deleteSurroundingText(2, 1)).isTrue();
+        verifyContent("145689", 4, 4, 1, 4);
+
+        // before commit: "1234|56789"
+        //                    - --
+        // before commit: "124|56|89"
+        //                   - --
+        prepareContent("123456789", 4, 4, 3, 6);
+        assertThat(mBaseInputConnection.deleteSurroundingText(1, 1)).isTrue();
+        verifyContent("1245689", 3, 3, 2, 5);
+    }
+
+    @Test
+    public void deleteSurroundingText_negativeLength_willBeIgnored() {
+        // before delete: "123|45678"
+        // after delete: "123|45678"
+        prepareContent("123456789", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.deleteSurroundingText(-1, -1)).isTrue();
+        verifyContent("123456789", 3, 3, -1, -1);
+
+        // before delete: "123|45678"
+        // after delete: "123|5678"
+        assertThat(mBaseInputConnection.deleteSurroundingText(-1, 1)).isTrue();
+        verifyContent("12356789", 3, 3, -1, -1);
+
+        // before delete: "123|45678"
+        // after delete: "12|45678"
+        prepareContent("123456789", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.deleteSurroundingText(1, -1)).isTrue();
+        verifyContent("12456789", 2, 2, -1, -1);
+    }
+
+    @Test
+    public void testFinishComposingText() {
+        // before finish composing: "123456|789"
+        //                             ---
+        // before finish composing: "123456|789"
+        prepareContent("123456789", 6, 6, 3, 6);
+        assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+        verifyContent("123456789", 6, 6, -1, -1);
+
+        // before finish composing: "123456789|"
+        //                             ---
+        // before finish composing: "123456789|"
+        prepareContent("123456789", 9, 9, 3, 6);
+        assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+        verifyContent("123456789", 9, 9, -1, -1);
+
+        // before finish composing: "|123456789|"
+        //                              ---
+        // before finish composing: "|123456789|"
+        prepareContent("123456789", 0, 9, 3, 6);
+        assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+        verifyContent("123456789", 0, 9, -1, -1);
+
+        // before finish composing: "1234|5|6789|"
+        //                           ---- - ----
+        // before finish composing: "1234|5|6789"
+        prepareContent("123456789", 4, 5, 0, 9);
+        assertThat(mBaseInputConnection.finishComposingText()).isTrue();
+        verifyContent("123456789", 4, 5, -1, -1);
+    }
+
+    @Test
+    public void testGetCursorCapsMode() {
+        // "|"
+        prepareContent("", 0, 0, -1, -1);
+        verifyCursorCapsModeWithMode("", 0);
+
+        // Hello|
+        prepareContent("Hello", 5, 5, -1, -1);
+        verifyCursorCapsModeWithMode("Hello", 5);
+
+        // Hello. |
+        prepareContent("Hello. ", 7, 7, -1, -1);
+        verifyCursorCapsModeWithMode("Hello. ", 7);
+
+        // Hello. |Hi|
+        prepareContent("Hello. Hi", 7, 9, -1, -1);
+        verifyCursorCapsModeWithMode("Hello. Hi", 7);
+
+        // Hello. |
+        // -----
+        prepareContent("Hello. ", 7, 7, 0, 5);
+        verifyCursorCapsModeWithMode("Hello. ", 7);
+    }
+
+    private void verifyCursorCapsModeWithMode(CharSequence text, int off) {
+        for (int reqMode : CURSOR_CAPS_MODES) {
+            assertThat(mBaseInputConnection.getCursorCapsMode(reqMode))
+                    .isEqualTo(TextUtils.getCapsMode(text, off, reqMode));
+        }
+    }
+
+    @Test
+    public void testSetComposingText_toEditorWithoutSelectionAndComposing() {
+        // before set composing text: "|"
+        // after set composing text: "abc|"
+        //                            ---
+        assertThat(mBaseInputConnection.setComposingText("abc", 1)).isTrue();
+        verifyContent("abc", 3, 3, 0, 3);
+
+        // before set composing text: "abc|"
+        // after set composing text: "abcdef|"
+        //                               ---
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingText("def", 100)).isTrue();
+        verifyContent("abcdef", 6, 6, 3, 6);
+
+        // before set composing text: "abc|"
+        // after set composing text: "abcdef|"
+        //                               ---
+        // BUG(b/21476564): this behavior is inconsistent with API description.
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingText("def", 0)).isTrue();
+        verifyContent("abcdef", 6, 6, 3, 6);
+
+        // before set composing text: "abc|"
+        // after set composing text: "ab|cdef"
+        //                                ---
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingText("def", -1)).isTrue();
+        verifyContent("abcdef", 2, 2, 3, 6);
+
+        // before set composing text: "abc|"
+        // after set composing text: "|abcdef"
+        //                                ---
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingText("def", -100)).isTrue();
+        verifyContent("abcdef", 0, 0, 3, 6);
+    }
+
+    @Test
+    public void testSetComposingText_toEditorWithComposing() {
+        // before set composing text: "abc|"
+        //                             ---
+        // after set composing text: "def|"
+        //                            ---
+        prepareContent("abc", 3, 3, 0, 3);
+        assertThat(mBaseInputConnection.setComposingText("def", 1)).isTrue();
+        verifyContent("def", 3, 3, 0, 3);
+
+        // before set composing text: "abc|"
+        //                             ---
+        // after set composing text: "hijkl|"
+        //                            -----
+        assertThat(mBaseInputConnection.setComposingText("hijkl", 1)).isTrue();
+        verifyContent("hijkl", 5, 5, 0, 5);
+
+        // before set composing text: "hijkl|"
+        //                             -----
+        // after set composing text: "|mn"
+        //                             --
+        assertThat(mBaseInputConnection.setComposingText("mn", 0)).isTrue();
+        verifyContent("mn", 0, 0, 0, 2);
+
+        // before set composing text: "|mn"
+        //                              --
+        // after set composing text: "|opq"
+        //                             ---
+        assertThat(mBaseInputConnection.setComposingText("opq", -1)).isTrue();
+        verifyContent("opq", 0, 0, 0, 3);
+    }
+
+    @Test
+    public void testSetComposingText_toEditorWithSelection() {
+        // before set composing text: "|abc|"
+        // after set composing text: "defgh|"
+        //                            -----
+        prepareContent("abc", 0, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingText("defgh", 1)).isTrue();
+        verifyContent("defgh", 5, 5, 0, 5);
+
+        // before set composing text: "a|bcdef|g"
+        // after set composing text: "a|123g"
+        //                              ---
+        prepareContent("abcdefg", 1, 6, -1, -1);
+        assertThat(mBaseInputConnection.setComposingText("123", 0)).isTrue();
+        verifyContent("a123g", 1, 1, 1, 4);
+
+        // before set composing text: "a|bcdef|g"
+        //                                ---
+        // after set composing text: "ab123456|fg"
+        //                              ------
+        prepareContent("abcdefg", 1, 6, 2, 5);
+        assertThat(mBaseInputConnection.setComposingText("123456", 1)).isTrue();
+        verifyContent("ab123456fg", 8, 8, 2, 8);
+
+        // before set composing text: "a|bc"
+        //                             ----
+        // after set composing text: "|12345"
+        //                             -----
+        prepareContent("abc", 1, 1, 0, 3);
+        assertThat(mBaseInputConnection.setComposingText("12345", -1)).isTrue();
+        verifyContent("12345", 0, 0, 0, 5);
+    }
+
+    @Test
+    public void testSetComposingRegion_toEditorWithoutSelectionAndComposing() {
+        // before set composing region: "|"
+        // after set composing region: "|"
+        assertThat(mBaseInputConnection.setComposingRegion(1, 1)).isTrue();
+        verifyContent("", 0, 0, -1, -1);
+
+        // before set composing region: "abc|"
+        // after set composing region: "abc|"
+        //                              ---
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(0, 3)).isTrue();
+        verifyContent("abc", 3, 3, 0, 3);
+
+        // before set composing region: "abc|"
+        // after set composing region: "abc|"
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(1, 1)).isTrue();
+        verifyContent("abc", 3, 3, -1, -1);
+
+        // before set composing region: "abc|"
+        // after set composing region: "abc|"
+        //                               -
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(1, 2)).isTrue();
+        verifyContent("abc", 3, 3, 1, 2);
+
+        // before set composing region: "abc|"
+        // after set composing region: "abc|"
+        //                              ---
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(3, 0)).isTrue();
+        verifyContent("abc", 3, 3, 0, 3);
+
+        // before set composing region: "abc|"
+        // after set composing region: "abc|"
+        //                              ---
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(-100, 100)).isTrue();
+        verifyContent("abc", 3, 3, 0, 3);
+    }
+
+    @Test
+    public void testSetComposingRegion_toEditorWithSelection() {
+        // before set composing region: "|abc|"
+        // after set composing region: "|abc|"
+        //                               ---
+        prepareContent("abc", 0, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(0, 3)).isTrue();
+        verifyContent("abc", 0, 3, 0, 3);
+
+        // before set composing region: "ab|cd|ef"
+        // after set composing region: "ab|cd|ef"
+        //                               - -- -
+        prepareContent("abcdef", 2, 4, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(1, 5)).isTrue();
+        verifyContent("abcdef", 2, 4, 1, 5);
+    }
+
+    @Test
+    public void testSetComposingRegion_toEditorWithComposing() {
+        // before set composing region: "abc|"
+        //                               ---
+        // after set composing region: "abc|"
+        //                               -
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setComposingRegion(1, 2)).isTrue();
+        verifyContent("abc", 3, 3, 1, 2);
+
+        // before set composing region: "ab|cd|ef"
+        //                                  --
+        // after set composing region: "ab|cd|ef"
+        //                               - -- -
+        prepareContent("abcdef", 2, 4, 2, 4);
+        assertThat(mBaseInputConnection.setComposingRegion(1, 5)).isTrue();
+        verifyContent("abcdef", 2, 4, 1, 5);
+    }
+
+    @Test
+    public void testSetSelection_toEditorWithoutComposing() {
+        // before set selection: "|"
+        // after set selection: "|"
+        assertThat(mBaseInputConnection.setSelection(0, 0)).isTrue();
+        assertThat(mBaseInputConnection.setSelection(1, 1)).isTrue();
+        assertThat(mBaseInputConnection.setSelection(-1, -1)).isTrue();
+
+        // before set selection: "abc|"
+        // after set selection: "a|b|c"
+        prepareContent("abc", 3, 3, -1, -1);
+        assertThat(mBaseInputConnection.setSelection(1, 1)).isTrue();
+        verifyContent("abc", 1, 1, -1, -1);
+
+        // before set selection: "abcdef|"
+        // after set selection: "ab|cd|ef"
+        prepareContent("abcdef", 6, 6, -1, -1);
+        assertThat(mBaseInputConnection.setSelection(4, 2)).isTrue();
+        verifyContent("abcdef", 4, 2, -1, -1);
+
+        // before set selection: "|abc"
+        // after set selection: "|abc"
+        prepareContent("abc", 0, 0, -1, -1);
+        assertThat(mBaseInputConnection.setSelection(0, 100)).isTrue();
+        verifyContent("abc", 0, 0, -1, -1);
+
+        // before set selection: "|abc"
+        // after set selection: "ab|c"
+        prepareContent("abc", 0, 0, -1, -1);
+        assertThat(mBaseInputConnection.setSelection(2, 2)).isTrue();
+        verifyContent("abc", 2, 2, -1, -1);
+
+        // before set selection: "|abc"
+        // after set selection: "|abc"
+        prepareContent("abc", 0, 0, -1, -1);
+        assertThat(mBaseInputConnection.setSelection(-1, 2)).isTrue();
+        verifyContent("abc", 0, 0, -1, -1);
+    }
+
+    @Test
+    public void testSetSelection_toEditorWithComposing() {
+        // before set selection: "abc|"
+        //                        ---
+        // after set selection: "a|bc"
+        //                       - --
+        prepareContent("abc", 3, 3, 0, 3);
+        assertThat(mBaseInputConnection.setSelection(1, 1)).isTrue();
+        verifyContent("abc", 1, 1, 0, 3);
+
+        // before set selection: "abcdef|"
+        //                          ---
+        // after set selection: "|abcdef|"
+        //                          ---
+        prepareContent("abcdef", 6, 6, 2, 5);
+        assertThat(mBaseInputConnection.setSelection(0, 6)).isTrue();
+        verifyContent("abcdef", 0, 6, 2, 5);
+    }
+
+    @Test
+    public void testGetText_noStyle() {
+        // "123|456|789"
+        prepareContent("123456789", 3, 6, -1, -1);
+
+        verifyContentEquals(mBaseInputConnection.getTextBeforeCursor(1, 0), "3");
+        verifyContentEquals(mBaseInputConnection.getTextAfterCursor(1, 0), "7");
+        verifyContentEquals(mBaseInputConnection.getSelectedText(0), "456");
+        // This falls back to default implementation in {@code InputConnection}, which always return
+        // -1 for offset.
+        assertThat(
+                        mBaseInputConnection
+                                .getSurroundingText(1, 1, 0)
+                                .isEqualTo(new SurroundingText("34567", 1, 4, -1)))
+                .isTrue();
+
+        verifyContentEquals(mBaseInputConnection.getTextBeforeCursor(100, 0), "123");
+        verifyContentEquals(mBaseInputConnection.getTextAfterCursor(100, 0), "789");
+        assertThat(
+                        mBaseInputConnection
+                                .getSurroundingText(100, 100, 0)
+                                .isEqualTo(new SurroundingText("123456789", 3, 6, -1)))
+                .isTrue();
+
+        verifyContentEquals(mBaseInputConnection.getTextBeforeCursor(0, 0), "");
+        verifyContentEquals(mBaseInputConnection.getTextAfterCursor(0, 0), "");
+        assertThat(
+                        mBaseInputConnection
+                                .getSurroundingText(0, 0, 0)
+                                .isEqualTo(new SurroundingText("456", 0, 3, -1)))
+                .isTrue();
+
+        int cursorCapsMode =
+                TextUtils.getCapsMode(
+                        "123456789",
+                        3,
+                        TextUtils.CAP_MODE_CHARACTERS
+                                | TextUtils.CAP_MODE_WORDS
+                                | TextUtils.CAP_MODE_SENTENCES);
+        TextSnapshot expectedTextSnapshot =
+                new TextSnapshot(
+                        new SurroundingText("123456789", 3, 6, -1), -1, -1, cursorCapsMode);
+        verifyTextSnapshotContentEquals(mBaseInputConnection.takeSnapshot(), expectedTextSnapshot);
+    }
+
+    @Test
+    public void testGetText_withStyle() {
+        // "123|456|789"
+        SpannableStringBuilder text = new SpannableStringBuilder("123456789");
+        SuggestionSpan suggestionSpanA =
+                new SuggestionSpan(Locale.US, new String[] {"a"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        SuggestionSpan suggestionSpanB =
+                new SuggestionSpan(Locale.US, new String[] {"b"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        SuggestionSpan suggestionSpanC =
+                new SuggestionSpan(Locale.US, new String[] {"c"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        text.setSpan(suggestionSpanA, 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        text.setSpan(suggestionSpanB, 3, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        text.setSpan(suggestionSpanC, 6, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        prepareContent(text, 3, 6, -1, -1);
+
+        verifySpannableString(
+                mBaseInputConnection.getTextBeforeCursor(1, InputConnection.GET_TEXT_WITH_STYLES),
+                "3",
+                1,
+                new int[][] {new int[] {0, 1}},
+                new Object[] {suggestionSpanA});
+        verifySpannableString(
+                mBaseInputConnection.getTextAfterCursor(1, InputConnection.GET_TEXT_WITH_STYLES),
+                "7",
+                1,
+                new int[][] {new int[] {0, 1}},
+                new Object[] {suggestionSpanC});
+        verifySpannableString(
+                mBaseInputConnection.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES),
+                "456",
+                1,
+                new int[][] {new int[] {0, 3}},
+                new Object[] {suggestionSpanB});
+        CharSequence surroundTextString =
+                TextUtils.concat(
+                        text.subSequence(0, 3), text.subSequence(3, 6), text.subSequence(6, 9));
+        assertThat(
+                        mBaseInputConnection
+                                .getSurroundingText(100, 100, InputConnection.GET_TEXT_WITH_STYLES)
+                                .isEqualTo(new SurroundingText(surroundTextString, 3, 6, -1)))
+                .isTrue();
+
+        int cursorCapsMode =
+                TextUtils.getCapsMode(
+                        "123456789",
+                        3,
+                        TextUtils.CAP_MODE_CHARACTERS
+                                | TextUtils.CAP_MODE_WORDS
+                                | TextUtils.CAP_MODE_SENTENCES);
+        TextSnapshot expectedTextSnapshot =
+                new TextSnapshot(
+                        new SurroundingText(surroundTextString, 3, 6, -1), -1, -1, cursorCapsMode);
+        verifyTextSnapshotContentEquals(mBaseInputConnection.takeSnapshot(), expectedTextSnapshot);
+    }
+
+    private void prepareContent(
+            CharSequence text,
+            int selectionStart,
+            int selectionEnd,
+            int composingSpanStart,
+            int composingSpanEnd) {
+        mEditable.clear();
+        mEditable.append(text);
+        Selection.setSelection(mEditable, selectionStart, selectionEnd);
+        if (isValidComposingSpan(text.length(), composingSpanStart, composingSpanEnd)) {
+            BaseInputConnection.setComposingSpans(mEditable, composingSpanStart, composingSpanEnd);
+        }
+        verifyContent(text, selectionStart, selectionEnd, composingSpanStart, composingSpanEnd);
+    }
+
+    private boolean isValidComposingSpan(
+            int textLength, int composingSpanStart, int composingSpanEnd) {
+        return composingSpanStart >= 0
+                && composingSpanStart <= textLength
+                && composingSpanEnd >= 0
+                && composingSpanEnd <= textLength;
+    }
+
+    private void verifyContent(
+            CharSequence text,
+            int selectionStart,
+            int selectionEnd,
+            int composingSpanStart,
+            int composingSpanEnd) {
+        assertThat(mEditable).isNotNull();
+        verifyContentEquals(mEditable, text.toString());
+        assertThat(Selection.getSelectionStart(mEditable)).isEqualTo(selectionStart);
+        assertThat(Selection.getSelectionEnd(mEditable)).isEqualTo(selectionEnd);
+        assertThat(BaseInputConnection.getComposingSpanStart(mEditable))
+                .isEqualTo(composingSpanStart);
+        assertThat(BaseInputConnection.getComposingSpanEnd(mEditable)).isEqualTo(composingSpanEnd);
+    }
+
+    private void verifySpannableString(
+            CharSequence text,
+            String expectedString,
+            int expectedSpanSize,
+            int[][] expectedSpanRanges,
+            Object[] expectedSpans) {
+        verifyContentEquals(text, expectedString);
+        SpannableStringBuilder spannableString = new SpannableStringBuilder(text);
+        Object[] spanList = spannableString.getSpans(0, text.length(), Object.class);
+        assertThat(spanList).isNotNull();
+        assertThat(spanList).hasLength(expectedSpanSize);
+        for (int i = 0; i < expectedSpanSize; i++) {
+            assertThat(spannableString.getSpanStart(spanList[i]))
+                    .isEqualTo(expectedSpanRanges[i][0]);
+            assertThat(spannableString.getSpanEnd(spanList[i])).isEqualTo(expectedSpanRanges[i][1]);
+        }
+        for (int i = 0; i < expectedSpanSize; i++) {
+            assertThat(spanList[i]).isEqualTo(expectedSpans[i]);
+        }
+    }
+
+    private void verifyContentEquals(CharSequence text, String expectedText) {
+        assertThat(text.toString().contentEquals(expectedText)).isTrue();
+    }
+
+    private void verifyTextSnapshotContentEquals(TextSnapshot t1, TextSnapshot t2) {
+        assertThat(t1.getCompositionStart()).isEqualTo(t2.getCompositionStart());
+        assertThat(t1.getCompositionEnd()).isEqualTo(t2.getCompositionEnd());
+        assertThat(t1.getCursorCapsMode()).isEqualTo(t2.getCursorCapsMode());
+        assertThat(t1.getSurroundingText().isEqualTo(t2.getSurroundingText())).isTrue();
+    }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java b/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
index 50ce335..047f330 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SurroundingTextTest.java
@@ -16,18 +16,21 @@
 
 package android.view.inputmethod;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertFalse;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Parcel;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.SuggestionSpan;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Locale;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class SurroundingTextTest {
@@ -35,22 +38,22 @@
     @Test
     public void testSurroundingTextBasicCreation() {
         SurroundingText surroundingText1 = new SurroundingText("test", 0, 0, 0);
-        assertThat(surroundingText1.getText(), is("test"));
-        assertThat(surroundingText1.getSelectionStart(), is(0));
-        assertThat(surroundingText1.getSelectionEnd(), is(0));
-        assertThat(surroundingText1.getOffset(), is(0));
+        assertThat(surroundingText1.getText().toString()).isEqualTo("test");
+        assertThat(surroundingText1.getSelectionStart()).isEqualTo(0);
+        assertThat(surroundingText1.getSelectionEnd()).isEqualTo(0);
+        assertThat(surroundingText1.getOffset()).isEqualTo(0);
 
         SurroundingText surroundingText2 = new SurroundingText("", -1, -1, -1);
-        assertThat(surroundingText2.getText(), is(""));
-        assertThat(surroundingText2.getSelectionStart(), is(-1));
-        assertThat(surroundingText2.getSelectionEnd(), is(-1));
-        assertThat(surroundingText2.getOffset(), is(-1));
+        assertThat(surroundingText2.getText().toString()).isEmpty();
+        assertThat(surroundingText2.getSelectionStart()).isEqualTo(-1);
+        assertThat(surroundingText2.getSelectionEnd()).isEqualTo(-1);
+        assertThat(surroundingText2.getOffset()).isEqualTo(-1);
 
         SurroundingText surroundingText3 = new SurroundingText("hello", 0, 5, 0);
-        assertThat(surroundingText3.getText(), is("hello"));
-        assertThat(surroundingText3.getSelectionStart(), is(0));
-        assertThat(surroundingText3.getSelectionEnd(), is(5));
-        assertThat(surroundingText3.getOffset(), is(0));
+        assertThat(surroundingText3.getText().toString()).isEqualTo("hello");
+        assertThat(surroundingText3.getSelectionStart()).isEqualTo(0);
+        assertThat(surroundingText3.getSelectionEnd()).isEqualTo(5);
+        assertThat(surroundingText3.getOffset()).isEqualTo(0);
     }
 
     @Test
@@ -62,20 +65,73 @@
         parcel.setDataPosition(0);
         SurroundingText surroundingTextFromParcel =
                 SurroundingText.CREATOR.createFromParcel(parcel);
-        assertThat(surroundingText.getText(), is("text"));
-        assertThat(surroundingText.getSelectionStart(), is(0));
-        assertThat(surroundingText.getSelectionEnd(), is(1));
-        assertThat(surroundingText.getOffset(), is(2));
-        assertThat(surroundingTextFromParcel.getText(), is("text"));
-        assertThat(surroundingTextFromParcel.getSelectionStart(), is(0));
-        assertThat(surroundingTextFromParcel.getSelectionEnd(), is(1));
-        assertThat(surroundingTextFromParcel.getOffset(), is(2));
+        assertThat(surroundingText.getText().toString()).isEqualTo("text");
+        assertThat(surroundingText.getSelectionStart()).isEqualTo(0);
+        assertThat(surroundingText.getSelectionEnd()).isEqualTo(1);
+        assertThat(surroundingText.getOffset()).isEqualTo(2);
+        assertThat(surroundingTextFromParcel.getText().toString()).isEqualTo("text");
+        assertThat(surroundingTextFromParcel.getSelectionStart()).isEqualTo(0);
+        assertThat(surroundingTextFromParcel.getSelectionEnd()).isEqualTo(1);
+        assertThat(surroundingTextFromParcel.getOffset()).isEqualTo(2);
     }
 
     @Test
-    public void testIsEqualComparesText() {
-        final SurroundingText text1 = new SurroundingText("hello", 0, 1, 0);
-        final SurroundingText text2 = new SurroundingText("there", 0, 1, 0);
-        assertFalse(text1.isEqualTo(text2));
+    public void testIsEqualComparesText_isNotEqualTo() {
+        final SurroundingText text = new SurroundingText("hello", 0, 1, 0);
+
+        verifySurroundingTextNotEquals(text, new SurroundingText("there", 0, 1, 0));
+        verifySurroundingTextNotEquals(text, new SurroundingText("hello", 0, 1, -1));
+        verifySurroundingTextNotEquals(text, new SurroundingText("hello", 0, 0, 0));
+        verifySurroundingTextNotEquals(text, new SurroundingText("hello", 1, 1, 0));
+
+        SpannableString spannableString = new SpannableString("hello");
+        spannableString.setSpan(
+                new SuggestionSpan(
+                        Locale.US, new String[] {"Hello"}, SuggestionSpan.FLAG_EASY_CORRECT),
+                0,
+                5,
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        verifySurroundingTextNotEquals(text, new SurroundingText(spannableString, 1, 1, 0));
+    }
+
+    private void verifySurroundingTextNotEquals(SurroundingText text1, SurroundingText text2) {
+        assertThat(text1.isEqualTo(text2)).isFalse();
+        assertThat(text1).isNotEqualTo(text2);
+        assertThat(text1.equals(text2)).isFalse();
+        assertThat(text1.hashCode()).isNotEqualTo(text2.hashCode());
+        assertThat(text1 == text2).isFalse();
+    }
+
+    @Test
+    public void testIsEqualComparesText_isEqualTo() {
+        final SurroundingText text = new SurroundingText("hello", 0, 1, 0);
+
+        verifySurroundingTextEquals(
+                text,
+                new SurroundingText("hello", 0, 1, 0),
+                /*equals=*/ false,
+                /*isSameInstance=*/ false);
+        verifySurroundingTextEquals(text, text, /*equals=*/ true, /*isSameInstance=*/ true);
+    }
+
+    private void verifySurroundingTextEquals(
+            SurroundingText text1, SurroundingText text2, boolean equals, boolean isSameInstance) {
+        assertThat(text1.isEqualTo(text2)).isTrue();
+        if (equals) {
+            assertThat(text1).isEqualTo(text2);
+            assertThat(text1.equals(text2)).isTrue();
+            assertThat(text1.hashCode()).isEqualTo(text2.hashCode());
+        } else {
+            assertThat(text1).isNotEqualTo(text2);
+            assertThat(text1.equals(text2)).isFalse();
+            assertThat(text1.hashCode()).isNotEqualTo(text2.hashCode());
+        }
+        if (isSameInstance) {
+            assertThat(text1 == text2).isTrue();
+            assertThat(text1).isSameInstanceAs(text2);
+        } else {
+            assertThat(text1 == text2).isFalse();
+            assertThat(text1).isNotSameInstanceAs(text2);
+        }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserListAdapterTest.kt b/core/tests/coretests/src/com/android/internal/app/ChooserListAdapterTest.kt
deleted file mode 100644
index f027e0b..0000000
--- a/core/tests/coretests/src/com/android/internal/app/ChooserListAdapterTest.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.app
-
-import android.content.ComponentName
-import android.content.pm.PackageManager
-import android.os.Bundle
-import android.service.chooser.ChooserTarget
-import android.view.View
-import android.widget.FrameLayout
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.R
-import com.android.internal.app.chooser.SelectableTargetInfo
-import com.android.internal.app.chooser.SelectableTargetInfo.SelectableTargetInfoCommunicator
-import com.android.server.testutils.any
-import com.android.server.testutils.mock
-import com.android.server.testutils.whenever
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-
-@RunWith(AndroidJUnit4::class)
-class ChooserListAdapterTest {
-    private val packageManager = mock<PackageManager> {
-        whenever(resolveActivity(any(), anyInt())).thenReturn(mock())
-    }
-    private val context = InstrumentationRegistry.getInstrumentation().getContext()
-    private val resolverListController = mock<ResolverListController>()
-    private val chooserListCommunicator = mock<ChooserListAdapter.ChooserListCommunicator> {
-        whenever(maxRankedTargets).thenReturn(0)
-    }
-    private val selectableTargetInfoCommunicator =
-        mock<SelectableTargetInfoCommunicator> {
-            whenever(targetIntent).thenReturn(mock())
-        }
-    private val chooserActivityLogger = mock<ChooserActivityLogger>()
-
-    private val testSubject = ChooserListAdapter(
-        context,
-        emptyList(),
-        emptyArray(),
-        emptyList(),
-        false,
-        resolverListController,
-        chooserListCommunicator,
-        selectableTargetInfoCommunicator,
-        packageManager,
-        chooserActivityLogger
-    )
-
-    @Test
-    fun testDirectShareTargetLoadingIconIsStarted() {
-        val view = createView()
-        val viewHolder = ResolverListAdapter.ViewHolder(view)
-        view.tag = viewHolder
-        val targetInfo = createSelectableTargetInfo()
-        val iconTask = mock<ChooserListAdapter.LoadDirectShareIconTask> {
-            doNothing().whenever(this).loadIcon()
-        }
-        testSubject.setTestLoadDirectShareTaskProvider(
-            mock {
-                whenever(get()).thenReturn(iconTask)
-            }
-        )
-        testSubject.testViewBind(view, targetInfo, 0)
-
-        verify(iconTask, times(1)).loadIcon()
-        verify(iconTask, times(1)).setViewHolder(viewHolder)
-    }
-
-    @Test
-    fun testOnlyOneTaskPerTarget() {
-        val view = createView()
-        val viewHolderOne = ResolverListAdapter.ViewHolder(view)
-        view.tag = viewHolderOne
-        val targetInfo = createSelectableTargetInfo()
-        val iconTaskOne = mock<ChooserListAdapter.LoadDirectShareIconTask> {
-            doNothing().whenever(this).loadIcon()
-        }
-        val testTaskProvider = mock<ChooserListAdapter.LoadDirectShareIconTaskProvider> {
-            whenever(get()).thenReturn(iconTaskOne)
-        }
-        testSubject.setTestLoadDirectShareTaskProvider(
-            testTaskProvider
-        )
-        testSubject.testViewBind(view, targetInfo, 0)
-
-        val viewHolderTwo = ResolverListAdapter.ViewHolder(view)
-        view.tag = viewHolderTwo
-        whenever(testTaskProvider.get()).thenReturn(mock())
-
-        testSubject.testViewBind(view, targetInfo, 0)
-
-        verify(iconTaskOne, times(1)).loadIcon()
-        verify(iconTaskOne, times(1)).setViewHolder(viewHolderOne)
-        verify(iconTaskOne, times(1)).setViewHolder(viewHolderTwo)
-        verify(testTaskProvider, times(1)).get()
-    }
-
-    private fun createSelectableTargetInfo(): SelectableTargetInfo =
-        SelectableTargetInfo(
-            context,
-            null,
-            createChooserTarget(),
-            1f,
-            selectableTargetInfoCommunicator,
-            null
-        )
-
-    private fun createChooserTarget(): ChooserTarget =
-        ChooserTarget(
-            "Title",
-            null,
-            1f,
-            ComponentName("package", "package.Class"),
-            Bundle()
-        )
-
-    private fun createView(): View {
-        val view = FrameLayout(context)
-        TextView(context).apply {
-            id = R.id.text1
-            view.addView(this)
-        }
-        TextView(context).apply {
-            id = R.id.text2
-            view.addView(this)
-        }
-        ImageView(context).apply {
-            id = R.id.icon
-            view.addView(this)
-        }
-        return view
-    }
-}
diff --git a/core/tests/coretests/src/com/android/internal/jank/DisplayResolutionTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/DisplayResolutionTrackerTest.java
new file mode 100644
index 0000000..5021022
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/jank/DisplayResolutionTrackerTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.jank;
+
+import static com.android.internal.jank.DisplayResolutionTracker.getResolution;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.DisplayManager;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+@SmallTest
+public class DisplayResolutionTrackerTest {
+    private static final DisplayInfo SD = makeDisplayInfo(800, 600);
+    private static final DisplayInfo HD = makeDisplayInfo(720, 1280);
+    private static final DisplayInfo FHD = makeDisplayInfo(2340, 1080);
+    private static final DisplayInfo QHD = makeDisplayInfo(3120, 1440);
+
+    private DisplayResolutionTracker.DisplayInterface mDisplayManager;
+    private ArgumentCaptor<DisplayManager.DisplayListener> mListenerCaptor;
+    private DisplayResolutionTracker mTracker;
+
+    @Before
+    public void setup() throws Exception {
+        mDisplayManager = mock(DisplayResolutionTracker.DisplayInterface.class);
+        mListenerCaptor = ArgumentCaptor.forClass(DisplayManager.DisplayListener.class);
+
+        mTracker = new DisplayResolutionTracker(mDisplayManager);
+
+        verify(mDisplayManager).registerDisplayListener(mListenerCaptor.capture());
+    }
+
+    @Test
+    public void testResolutionMapping() {
+        assertThat(getResolution(SD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_SD);
+        assertThat(getResolution(HD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_HD);
+        assertThat(getResolution(FHD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_FHD);
+        assertThat(getResolution(QHD)).isEqualTo(DisplayResolutionTracker.RESOLUTION_QHD);
+    }
+
+    @Test
+    public void testResolutionUpdatesOnDisplayChanges() throws Exception {
+        assertThat(mTracker.getResolution(42))
+                .isEqualTo(DisplayResolutionTracker.RESOLUTION_UNKNOWN);
+
+        when(mDisplayManager.getDisplayInfo(42)).thenReturn(FHD, QHD);
+
+        mListenerCaptor.getValue().onDisplayAdded(42);
+        assertThat(mTracker.getResolution(42))
+                .isEqualTo(DisplayResolutionTracker.RESOLUTION_FHD);
+        mListenerCaptor.getValue().onDisplayChanged(42);
+        assertThat(mTracker.getResolution(42))
+                .isEqualTo(DisplayResolutionTracker.RESOLUTION_QHD);
+    }
+
+    private static DisplayInfo makeDisplayInfo(int width, int height) {
+        DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = width;
+        info.logicalHeight = height;
+        return info;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index e068730..dbbd705 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -124,6 +124,7 @@
         when(config.isSurfaceOnly()).thenReturn(surfaceOnly);
         when(config.getSurfaceControl()).thenReturn(mSurfaceControl);
         when(config.shouldDeferMonitor()).thenReturn(true);
+        when(config.getDisplayId()).thenReturn(42);
         View view = mRule.getActivity().getWindow().getDecorView();
         Handler spyHandler = spy(new Handler(handler.getLooper()));
         when(config.getView()).thenReturn(surfaceOnly ? null : view);
@@ -168,6 +169,7 @@
         verify(tracker).removeObservers();
         verify(tracker, never()).triggerPerfetto();
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -204,6 +206,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -240,6 +243,7 @@
         verify(tracker, never()).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -276,6 +280,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -315,6 +320,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -356,6 +362,7 @@
         verify(tracker).removeObservers();
         verify(tracker, never()).triggerPerfetto();
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -483,6 +490,7 @@
         verify(tracker).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(2L) /* totalFrames */,
                 eq(1L) /* missedFrames */,
@@ -519,6 +527,7 @@
         verify(tracker, never()).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -555,6 +564,7 @@
         verify(tracker, never()).triggerPerfetto();
 
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(2L) /* totalFrames */,
                 eq(0L) /* missedFrames */,
@@ -585,6 +595,7 @@
         verify(mSurfaceControlWrapper).removeJankStatsListener(any());
         verify(tracker).triggerPerfetto();
         verify(mStatsLog).write(eq(UI_INTERACTION_FRAME_INFO_REPORTED),
+                eq(42), /* displayId */
                 eq(CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WALLPAPER_TRANSITION]),
                 eq(6L) /* totalFrames */,
                 eq(5L) /* missedFrames */,
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 1519e48..4770fa6 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -354,10 +354,11 @@
         when(configuration.isSurfaceOnly()).thenReturn(false);
         when(configuration.getView()).thenReturn(mView);
         when(configuration.getHandler()).thenReturn(mView.getHandler());
+        when(configuration.getDisplayId()).thenReturn(42);
 
         FrameTracker tracker = spy(new FrameTracker(monitor, session, mWorker.getThreadHandler(),
                 threadedRenderer, viewRoot, surfaceControl, choreographer,
-                new FrameMetricsWrapper(), new StatsLogWrapper(),
+                new FrameMetricsWrapper(), new StatsLogWrapper(null),
                 /* traceThresholdMissedFrames= */ 1,
                 /* traceThresholdFrameTimeMillis= */ -1, listener, configuration));
 
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index a22dd1c..516dee7 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -161,4 +161,33 @@
         assertThrows(RuntimeException.class,
                 () -> LongArrayMultiStateCounter.CREATOR.createFromParcel(parcel));
     }
+
+    @Test
+    public void combineValues() {
+        long[] values = new long[] {0, 1, 2, 3, 42};
+        LongArrayMultiStateCounter.LongArrayContainer container =
+                new LongArrayMultiStateCounter.LongArrayContainer(values.length);
+        container.setValues(values);
+
+        long[] out = new long[3];
+        int[] indexes = {2, 1, 1, 0, 0};
+        boolean nonZero = container.combineValues(out, indexes);
+        assertThat(nonZero).isTrue();
+        assertThat(out).isEqualTo(new long[]{45, 3, 0});
+
+        // All zeros
+        container.setValues(new long[]{0, 0, 0, 0, 0});
+        nonZero = container.combineValues(out, indexes);
+        assertThat(nonZero).isFalse();
+        assertThat(out).isEqualTo(new long[]{0, 0, 0});
+
+        // Index out of range
+        IndexOutOfBoundsException e1 = assertThrows(
+                IndexOutOfBoundsException.class,
+                () -> container.combineValues(out, new int[]{0, 1, -1, 0, 0}));
+        assertThat(e1.getMessage()).isEqualTo("Index -1 is out of bounds: [0, 2]");
+        IndexOutOfBoundsException e2 = assertThrows(IndexOutOfBoundsException.class,
+                () -> container.combineValues(out, new int[]{0, 1, 4, 0, 0}));
+        assertThat(e2.getMessage()).isEqualTo("Index 4 is out of bounds: [0, 2]");
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
index bc3b422..6a3d379 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
@@ -21,6 +21,11 @@
 import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL;
 import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
 import android.annotation.XmlRes;
 import android.content.Context;
 import android.content.res.Resources;
@@ -28,15 +33,16 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 import com.android.internal.power.ModemPowerProfile;
 import com.android.internal.util.XmlUtils;
 
-import junit.framework.TestCase;
-
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /*
  * Keep this file in sync with frameworks/base/core/res/res/xml/power_profile_test.xml and
@@ -46,7 +52,8 @@
  *     atest com.android.internal.os.PowerProfileTest
  */
 @SmallTest
-public class PowerProfileTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class PowerProfileTest {
 
     static final String TAG_TEST_MODEM = "test-modem";
     static final String ATTR_NAME = "name";
@@ -516,4 +523,66 @@
         fail("Unanable to find element " + element + " with name " + elementName);
         return null;
     }
+
+    private void assertEquals(int expected, int actual) {
+        Assert.assertEquals(expected, actual);
+    }
+
+    private void assertEquals(double expected, double actual) {
+        Assert.assertEquals(expected, actual, 0.1);
+    }
+
+
+    @Test
+    public void powerBrackets_specifiedInPowerProfile() {
+        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test_power_brackets);
+        mProfile.initCpuPowerBrackets(8);
+
+        int cpuPowerBracketCount = mProfile.getCpuPowerBracketCount();
+        assertThat(cpuPowerBracketCount).isEqualTo(2);
+        assertThat(new int[]{
+                mProfile.getPowerBracketForCpuCore(0, 0),
+                mProfile.getPowerBracketForCpuCore(1, 0),
+                mProfile.getPowerBracketForCpuCore(1, 1),
+        }).isEqualTo(new int[]{1, 1, 0});
+    }
+
+    @Test
+    public void powerBrackets_automatic() {
+        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test);
+
+        assertThat(mProfile.getCpuPowerBracketCount()).isEqualTo(3);
+        assertThat(mProfile.getCpuPowerBracketDescription(0))
+                .isEqualTo("0/300(10.0)");
+        assertThat(mProfile.getCpuPowerBracketDescription(1))
+                .isEqualTo("0/1000(20.0), 0/2000(30.0), 1/300(25.0)");
+        assertThat(mProfile.getCpuPowerBracketDescription(2))
+                .isEqualTo("1/1000(35.0), 1/2500(50.0), 1/3000(60.0)");
+        assertThat(new int[]{
+                mProfile.getPowerBracketForCpuCore(0, 0),
+                mProfile.getPowerBracketForCpuCore(0, 1),
+                mProfile.getPowerBracketForCpuCore(0, 2),
+                mProfile.getPowerBracketForCpuCore(1, 0),
+                mProfile.getPowerBracketForCpuCore(1, 1),
+                mProfile.getPowerBracketForCpuCore(1, 2),
+                mProfile.getPowerBracketForCpuCore(1, 3),
+        }).isEqualTo(new int[]{0, 1, 1, 1, 2, 2, 2});
+    }
+
+    @Test
+    public void powerBrackets_moreBracketsThanStates() {
+        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test);
+        mProfile.initCpuPowerBrackets(8);
+
+        assertThat(mProfile.getCpuPowerBracketCount()).isEqualTo(7);
+        assertThat(new int[]{
+                mProfile.getPowerBracketForCpuCore(0, 0),
+                mProfile.getPowerBracketForCpuCore(0, 1),
+                mProfile.getPowerBracketForCpuCore(0, 2),
+                mProfile.getPowerBracketForCpuCore(1, 0),
+                mProfile.getPowerBracketForCpuCore(1, 1),
+                mProfile.getPowerBracketForCpuCore(1, 2),
+                mProfile.getPowerBracketForCpuCore(1, 3),
+        }).isEqualTo(new int[]{0, 1, 2, 3, 4, 5, 6});
+    }
 }
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index c117816..af96c74 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -246,6 +246,9 @@
 key 224   BRIGHTNESS_DOWN
 key 225   BRIGHTNESS_UP
 key 226   HEADSETHOOK
+key 228   KEYBOARD_BACKLIGHT_TOGGLE
+key 229   KEYBOARD_BACKLIGHT_DOWN
+key 230   KEYBOARD_BACKLIGHT_UP
 
 key 256   BUTTON_1
 key 257   BUTTON_2
@@ -299,6 +302,11 @@
 key 318   BUTTON_THUMBR
 
 
+key 329   STYLUS_BUTTON_TERTIARY
+key 331   STYLUS_BUTTON_PRIMARY
+key 332   STYLUS_BUTTON_SECONDARY
+
+
 # key 352 "KEY_OK"
 key 353   DPAD_CENTER
 # key 354 "KEY_GOTO"
@@ -415,9 +423,14 @@
 key usage 0x0c0067 WINDOW
 key usage 0x0c006F BRIGHTNESS_UP
 key usage 0x0c0070 BRIGHTNESS_DOWN
+key usage 0x0c0079 KEYBOARD_BACKLIGHT_UP
+key usage 0x0c007A KEYBOARD_BACKLIGHT_DOWN
+key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE
 key usage 0x0c0173 MEDIA_AUDIO_TRACK
 key usage 0x0c019C PROFILE_SWITCH
 key usage 0x0c01A2 ALL_APPS
+key usage 0x0d0044 STYLUS_BUTTON_PRIMARY
+key usage 0x0d005a STYLUS_BUTTON_SECONDARY
 
 # Joystick and game controller axes.
 # Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
diff --git a/docs/html/reference/images/input_method/stylus_handwriting/delete_range_gesture_rects.png b/docs/html/reference/images/input_method/stylus_handwriting/delete_range_gesture_rects.png
new file mode 100644
index 0000000..1855820
--- /dev/null
+++ b/docs/html/reference/images/input_method/stylus_handwriting/delete_range_gesture_rects.png
Binary files differ
diff --git a/docs/html/reference/images/input_method/stylus_handwriting/select_range_gesture_rects.png b/docs/html/reference/images/input_method/stylus_handwriting/select_range_gesture_rects.png
new file mode 100644
index 0000000..e080126
--- /dev/null
+++ b/docs/html/reference/images/input_method/stylus_handwriting/select_range_gesture_rects.png
Binary files differ
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index a8ab6d9..54d6428 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -670,8 +670,9 @@
     /**
      * @hide
      */
-    public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
-        nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
+    public void punchHole(float left, float top, float right, float bottom, float rx, float ry,
+            float alpha) {
+        nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha);
     }
 
     /**
@@ -823,5 +824,5 @@
             float hOffset, float vOffset, int flags, long nativePaint);
 
     private static native void nPunchHole(long renderer, float left, float top, float right,
-            float bottom, float rx, float ry);
+            float bottom, float rx, float ry, float alpha);
 }
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index d06f665..1ba79b8 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -610,8 +610,9 @@
      * @hide
      */
     @Override
-    public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
-        nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
+    public void punchHole(float left, float top, float right, float bottom, float rx, float ry,
+            float alpha) {
+        nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha);
     }
 
     @FastNative
@@ -742,5 +743,5 @@
 
     @FastNative
     private static native void nPunchHole(long renderer, float left, float top, float right,
-            float bottom, float rx, float ry);
+            float bottom, float rx, float ry, float alpha);
 }
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 052b9af..81b8542 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -33,7 +33,7 @@
  * (based on the paint's Style), or it can be used for clipping or to draw
  * text on a path.
  */
-public class Path implements Iterable<PathIterator.Segment> {
+public class Path {
 
     private static final NativeAllocationRegistry sRegistry =
             NativeAllocationRegistry.createMalloced(
@@ -97,8 +97,7 @@
      * @return the Iterator object
      */
     @NonNull
-    @Override
-    public PathIterator iterator() {
+    public PathIterator getPathIterator() {
         return new PathIterator(this);
     }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 724a50f..126f835 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -139,6 +139,16 @@
         }
     }
 
+    @Override
+    public void setSplitAttributesCalculator(@NonNull SplitAttributesCalculator calculator) {
+        // TODO: Implement this method
+    }
+
+    @Override
+    public void clearSplitAttributesCalculator() {
+        // TODO: Implement this method
+    }
+
     @NonNull
     List<EmbeddingRule> getSplitRules() {
         return mSplitRules;
@@ -901,6 +911,36 @@
         mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
     }
 
+    @Nullable
+    @GuardedBy("mLock")
+    private TaskFragmentContainer resolveStartActivityIntentFromNonActivityContext(
+            @NonNull WindowContainerTransaction wct, @NonNull Intent intent) {
+        final int taskCount = mTaskContainers.size();
+        if (taskCount == 0) {
+            // We don't have other Activity to check split with.
+            return null;
+        }
+        if (taskCount > 1) {
+            Log.w(TAG, "App is calling startActivity from a non-Activity context when it has"
+                    + " more than one Task. If the new launch Activity is in a different process,"
+                    + " and it is expected to be embedded, please start it from an Activity"
+                    + " instead.");
+            return null;
+        }
+
+        // Check whether the Intent should be embedded in the known Task.
+        final TaskContainer taskContainer = mTaskContainers.valueAt(0);
+        if (taskContainer.isInPictureInPicture()
+                || taskContainer.getTopNonFinishingActivity() == null) {
+            // We don't embed activity when it is in PIP, or if we can't find any other owner
+            // activity in the Task.
+            return null;
+        }
+
+        return resolveStartActivityIntent(wct, taskContainer.getTaskId(), intent,
+                null /* launchingActivity */);
+    }
+
     /**
      * When we are trying to handle a new activity Intent, returns the {@link TaskFragmentContainer}
      * that we should reparent the new activity to if there is any embedding rule matched.
@@ -1486,13 +1526,20 @@
                         .toActivityStack();
                 final ActivityStack secondaryContainer = container.getSecondaryContainer()
                         .toActivityStack();
+                final SplitAttributes.SplitType splitType = shouldShowSideBySide(container)
+                        ? new SplitAttributes.SplitType.RatioSplitType(
+                                container.getSplitRule().getSplitRatio())
+                        : new SplitAttributes.SplitType.ExpandContainersSplitType();
                 final SplitInfo splitState = new SplitInfo(primaryContainer, secondaryContainer,
                         // Splits that are not showing side-by-side are reported as having 0 split
                         // ratio, since by definition in the API the primary container occupies no
                         // width of the split when covered by the secondary.
-                        shouldShowSideBySide(container)
-                                ? container.getSplitRule().getSplitRatio()
-                                : 0.0f);
+                        // TODO(b/241042437): use v2 APIs for splitAttributes
+                        new SplitAttributes.Builder()
+                                .setSplitType(splitType)
+                                .setLayoutDirection(container.getSplitRule().getLayoutDirection())
+                                .build()
+                        );
                 splitStates.add(splitState);
             }
         }
@@ -1777,23 +1824,38 @@
         @Override
         public Instrumentation.ActivityResult onStartActivity(@NonNull Context who,
                 @NonNull Intent intent, @NonNull Bundle options) {
-            // TODO(b/190433398): Check if the activity is configured to always be expanded.
+            // TODO(b/232042367): Consolidate the activity create handling so that we can handle
+            // cross-process the same as normal.
 
-            // Check if activity should be put in a split with the activity that launched it.
-            if (!(who instanceof Activity)) {
-                return super.onStartActivity(who, intent, options);
-            }
-            final Activity launchingActivity = (Activity) who;
-            if (isInPictureInPicture(launchingActivity)) {
-                // We don't embed activity when it is in PIP.
-                return super.onStartActivity(who, intent, options);
+            final Activity launchingActivity;
+            if (who instanceof Activity) {
+                // We will check if the new activity should be split with the activity that launched
+                // it.
+                launchingActivity = (Activity) who;
+                if (isInPictureInPicture(launchingActivity)) {
+                    // We don't embed activity when it is in PIP.
+                    return super.onStartActivity(who, intent, options);
+                }
+            } else {
+                // When the context to start activity is not an Activity context, we will check if
+                // the new activity should be embedded in the known Task belonging to the organizer
+                // process. @see #resolveStartActivityIntentFromNonActivityContext
+                // It is a current security limitation that we can't access the activity info of
+                // other process even if it is in the same Task.
+                launchingActivity = null;
             }
 
             synchronized (mLock) {
-                final int taskId = getTaskId(launchingActivity);
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
-                final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct,
-                        taskId, intent, launchingActivity);
+                final TaskFragmentContainer launchedInTaskFragment;
+                if (launchingActivity != null) {
+                    final int taskId = getTaskId(launchingActivity);
+                    launchedInTaskFragment = resolveStartActivityIntent(wct, taskId, intent,
+                            launchingActivity);
+                } else {
+                    launchedInTaskFragment = resolveStartActivityIntentFromNonActivityContext(wct,
+                            intent);
+                }
                 if (launchedInTaskFragment != null) {
                     // Make sure the WCT is applied immediately instead of being queued so that the
                     // TaskFragment will be ready before activity attachment.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index cdee9e3..af5d8c5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -16,7 +16,6 @@
 
 package androidx.window.extensions.embedding;
 
-import static android.graphics.Matrix.MSCALE_X;
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
 
@@ -41,30 +40,44 @@
      */
     private static final int LAYER_NO_OVERRIDE = -1;
 
+    @NonNull
     final Animation mAnimation;
+    @NonNull
     final RemoteAnimationTarget mTarget;
+    @NonNull
     final SurfaceControl mLeash;
+    /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
+    @NonNull
+    private final Rect mWholeAnimationBounds = new Rect();
 
+    @NonNull
     final Transformation mTransformation = new Transformation();
+    @NonNull
     final float[] mMatrix = new float[9];
+    @NonNull
     final float[] mVecs = new float[4];
+    @NonNull
     final Rect mRect = new Rect();
     private boolean mIsFirstFrame = true;
     private int mOverrideLayer = LAYER_NO_OVERRIDE;
 
     TaskFragmentAnimationAdapter(@NonNull Animation animation,
             @NonNull RemoteAnimationTarget target) {
-        this(animation, target, target.leash);
+        this(animation, target, target.leash, target.screenSpaceBounds);
     }
 
     /**
      * @param leash the surface to animate.
+     * @param wholeAnimationBounds  area in absolute coordinate that the animation surface shouldn't
+     *                              go beyond.
      */
     TaskFragmentAnimationAdapter(@NonNull Animation animation,
-            @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash) {
+            @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
+            @NonNull Rect wholeAnimationBounds) {
         mAnimation = animation;
         mTarget = target;
         mLeash = leash;
+        mWholeAnimationBounds.set(wholeAnimationBounds);
     }
 
     /**
@@ -94,23 +107,32 @@
 
     /** To be overridden by subclasses to adjust the animation surface change. */
     void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+        // Update the surface position and alpha.
         mTransformation.getMatrix().postTranslate(
                 mTarget.localBounds.left, mTarget.localBounds.top);
         t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
         t.setAlpha(mLeash, mTransformation.getAlpha());
-        // Get current animation position.
+
+        // Get current surface bounds in absolute coordinate.
+        // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
         final int positionX = Math.round(mMatrix[MTRANS_X]);
         final int positionY = Math.round(mMatrix[MTRANS_Y]);
-        // The exiting surface starts at position: mTarget.localBounds and moves with
-        // positionX varying. Offset our crop region by the amount we have slided so crop
-        // regions stays exactly on the original container in split.
-        final int cropOffsetX = mTarget.localBounds.left - positionX;
-        final int cropOffsetY = mTarget.localBounds.top - positionY;
-        final Rect cropRect = new Rect();
-        cropRect.set(mTarget.localBounds);
-        // Because window crop uses absolute position.
-        cropRect.offsetTo(0, 0);
-        cropRect.offset(cropOffsetX, cropOffsetY);
+        final Rect cropRect = new Rect(mTarget.screenSpaceBounds);
+        final Rect localBounds = mTarget.localBounds;
+        cropRect.offset(positionX - localBounds.left, positionY - localBounds.top);
+
+        // Store the current offset of the surface top left from (0,0) in absolute coordinate.
+        final int offsetX = cropRect.left;
+        final int offsetY = cropRect.top;
+
+        // Intersect to make sure the animation happens within the whole animation bounds.
+        if (!cropRect.intersect(mWholeAnimationBounds)) {
+            // Hide the surface when it is outside of the animation area.
+            t.setAlpha(mLeash, 0);
+        }
+
+        // cropRect is in absolute coordinate, so we need to translate it to surface top left.
+        cropRect.offset(-offsetX, -offsetY);
         t.setCrop(mLeash, cropRect);
     }
 
@@ -124,52 +146,6 @@
     }
 
     /**
-     * Should be used when the {@link RemoteAnimationTarget} is in split with others, and want to
-     * animate together as one. This adapter will offset the animation leash to make the animate of
-     * two windows look like a single window.
-     */
-    static class SplitAdapter extends TaskFragmentAnimationAdapter {
-        private final boolean mIsLeftHalf;
-        private final int mWholeAnimationWidth;
-
-        /**
-         * @param isLeftHalf whether this is the left half of the animation.
-         * @param wholeAnimationWidth the whole animation windows width.
-         */
-        SplitAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target,
-                boolean isLeftHalf, int wholeAnimationWidth) {
-            super(animation, target);
-            mIsLeftHalf = isLeftHalf;
-            mWholeAnimationWidth = wholeAnimationWidth;
-            if (wholeAnimationWidth == 0) {
-                throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
-            }
-        }
-
-        @Override
-        void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
-            float posX = mTarget.localBounds.left;
-            final float posY = mTarget.localBounds.top;
-            // This window is half of the whole animation window. Offset left/right to make it
-            // look as one with the other half.
-            mTransformation.getMatrix().getValues(mMatrix);
-            final int targetWidth = mTarget.localBounds.width();
-            final float scaleX = mMatrix[MSCALE_X];
-            final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
-            final float curOffset = targetWidth * (1 - scaleX) / 2;
-            final float offsetDiff = totalOffset - curOffset;
-            if (mIsLeftHalf) {
-                posX += offsetDiff;
-            } else {
-                posX -= offsetDiff;
-            }
-            mTransformation.getMatrix().postTranslate(posX, posY);
-            t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
-            t.setAlpha(mLeash, mTransformation.getAlpha());
-        }
-    }
-
-    /**
      * Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
      * size change.
      */
@@ -177,7 +153,7 @@
 
         SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
             // Start leash is the snapshot of the starting surface.
-            super(animation, target, target.startLeash);
+            super(animation, target, target.startLeash, target.screenSpaceBounds);
         }
 
         @Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 8af2d9c..8c416e8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -213,10 +213,10 @@
         for (RemoteAnimationTarget target : targets) {
             if (target.mode != MODE_CLOSING) {
                 openingTargets.add(target);
-                openingWholeScreenBounds.union(target.localBounds);
+                openingWholeScreenBounds.union(target.screenSpaceBounds);
             } else {
                 closingTargets.add(target);
-                closingWholeScreenBounds.union(target.localBounds);
+                closingWholeScreenBounds.union(target.screenSpaceBounds);
             }
         }
 
@@ -249,20 +249,8 @@
             @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
             @NonNull Rect wholeAnimationBounds) {
         final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
-        final Rect targetBounds = target.localBounds;
-        if (targetBounds.left == wholeAnimationBounds.left
-                && targetBounds.right != wholeAnimationBounds.right) {
-            // This is the left split of the whole animation window.
-            return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
-                    true /* isLeftHalf */, wholeAnimationBounds.width());
-        } else if (targetBounds.left != wholeAnimationBounds.left
-                && targetBounds.right == wholeAnimationBounds.right) {
-            // This is the right split of the whole animation window.
-            return new TaskFragmentAnimationAdapter.SplitAdapter(animation, target,
-                    false /* isLeftHalf */, wholeAnimationBounds.width());
-        }
-        // Open/close window that fills the whole animation.
-        return new TaskFragmentAnimationAdapter(animation, target);
+        return new TaskFragmentAnimationAdapter(animation, target, target.leash,
+                wholeAnimationBounds);
     }
 
     @NonNull
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 97d42391b..ef5ea56 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -195,7 +195,10 @@
                     ? com.android.internal.R.anim.task_fragment_open_enter
                     : com.android.internal.R.anim.task_fragment_open_exit);
         }
-        animation.initialize(target.localBounds.width(), target.localBounds.height(),
+        // Use the whole animation bounds instead of the change bounds, so that when multiple change
+        // targets are opening at the same time, the animation applied to each will be the same.
+        // Otherwise, we may see gap between the activities that are launching together.
+        animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
                 wholeAnimationBounds.width(), wholeAnimationBounds.height());
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         return animation;
@@ -215,7 +218,10 @@
                     ? com.android.internal.R.anim.task_fragment_close_enter
                     : com.android.internal.R.anim.task_fragment_close_exit);
         }
-        animation.initialize(target.localBounds.width(), target.localBounds.height(),
+        // Use the whole animation bounds instead of the change bounds, so that when multiple change
+        // targets are closing at the same time, the animation applied to each will be the same.
+        // Otherwise, we may see gap between the activities that are finishing together.
+        animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
                 wholeAnimationBounds.width(), wholeAnimationBounds.height());
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         return animation;
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index e9a1721..2c766d8 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index b5409b7..dec1e38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -44,6 +44,7 @@
 import android.util.SparseArray;
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizerController;
+import android.window.ScreenCapture;
 import android.window.StartingWindowInfo;
 import android.window.StartingWindowRemovalInfo;
 import android.window.TaskAppearedInfo;
@@ -474,7 +475,7 @@
      * Take a screenshot of a task.
      */
     public void screenshotTask(RunningTaskInfo taskInfo, Rect crop,
-            Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
+            Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) {
         final TaskAppearedInfo info = mTasks.get(taskInfo.taskId);
         if (info == null) {
             return;
@@ -876,8 +877,12 @@
                     pkg = info.getTaskInfo().baseActivity.getPackageName();
                 }
                 Rect bounds = info.getTaskInfo().getConfiguration().windowConfiguration.getBounds();
+                boolean running = info.getTaskInfo().isRunning;
+                boolean visible = info.getTaskInfo().isVisible;
+                boolean focused = info.getTaskInfo().isFocused;
                 pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener
-                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds);
+                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds
+                        + " running=" + running + " visible=" + visible + " focused=" + focused);
             }
 
             pw.println();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TEST_MAPPING b/libs/WindowManager/Shell/src/com/android/wm/shell/TEST_MAPPING
new file mode 100644
index 0000000..8dd1369
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "ironwood-postsubmit": [
+    {
+      "name": "WMShellFlickerTests",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.IwTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ]
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index cc4db93..591e347 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.activityembedding;
 
-import static android.graphics.Matrix.MSCALE_X;
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
 
@@ -42,31 +41,45 @@
      */
     private static final int LAYER_NO_OVERRIDE = -1;
 
+    @NonNull
     final Animation mAnimation;
+    @NonNull
     final TransitionInfo.Change mChange;
+    @NonNull
     final SurfaceControl mLeash;
+    /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
+    @NonNull
+    private final Rect mWholeAnimationBounds = new Rect();
 
+    @NonNull
     final Transformation mTransformation = new Transformation();
+    @NonNull
     final float[] mMatrix = new float[9];
+    @NonNull
     final float[] mVecs = new float[4];
+    @NonNull
     final Rect mRect = new Rect();
     private boolean mIsFirstFrame = true;
     private int mOverrideLayer = LAYER_NO_OVERRIDE;
 
     ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
             @NonNull TransitionInfo.Change change) {
-        this(animation, change, change.getLeash());
+        this(animation, change, change.getLeash(), change.getEndAbsBounds());
     }
 
     /**
      * @param leash the surface to animate, which is not necessary the same as
-     * {@link TransitionInfo.Change#getLeash()}, it can be a screenshot for example.
+     *              {@link TransitionInfo.Change#getLeash()}, it can be a screenshot for example.
+     * @param wholeAnimationBounds  area in absolute coordinate that the animation surface shouldn't
+     *                              go beyond.
      */
     ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
-            @NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash) {
+            @NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash,
+            @NonNull Rect wholeAnimationBounds) {
         mAnimation = animation;
         mChange = change;
         mLeash = leash;
+        mWholeAnimationBounds.set(wholeAnimationBounds);
     }
 
     /**
@@ -96,23 +109,31 @@
 
     /** To be overridden by subclasses to adjust the animation surface change. */
     void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+        // Update the surface position and alpha.
         final Point offset = mChange.getEndRelOffset();
         mTransformation.getMatrix().postTranslate(offset.x, offset.y);
         t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
         t.setAlpha(mLeash, mTransformation.getAlpha());
-        // Get current animation position.
+
+        // Get current surface bounds in absolute coordinate.
+        // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
         final int positionX = Math.round(mMatrix[MTRANS_X]);
         final int positionY = Math.round(mMatrix[MTRANS_Y]);
-        // The exiting surface starts at position: Change#getEndRelOffset() and moves with
-        // positionX varying. Offset our crop region by the amount we have slided so crop
-        // regions stays exactly on the original container in split.
-        final int cropOffsetX = offset.x - positionX;
-        final int cropOffsetY = offset.y - positionY;
-        final Rect cropRect = new Rect();
-        cropRect.set(mChange.getEndAbsBounds());
-        // Because window crop uses absolute position.
-        cropRect.offsetTo(0, 0);
-        cropRect.offset(cropOffsetX, cropOffsetY);
+        final Rect cropRect = new Rect(mChange.getEndAbsBounds());
+        cropRect.offset(positionX - offset.x, positionY - offset.y);
+
+        // Store the current offset of the surface top left from (0,0) in absolute coordinate.
+        final int offsetX = cropRect.left;
+        final int offsetY = cropRect.top;
+
+        // Intersect to make sure the animation happens within the whole animation bounds.
+        if (!cropRect.intersect(mWholeAnimationBounds)) {
+            // Hide the surface when it is outside of the animation area.
+            t.setAlpha(mLeash, 0);
+        }
+
+        // cropRect is in absolute coordinate, so we need to translate it to surface top left.
+        cropRect.offset(-offsetX, -offsetY);
         t.setCrop(mLeash, cropRect);
     }
 
@@ -127,53 +148,6 @@
     }
 
     /**
-     * Should be used when the {@link TransitionInfo.Change} is in split with others, and wants to
-     * animate together as one. This adapter will offset the animation leash to make the animate of
-     * two windows look like a single window.
-     */
-    static class SplitAdapter extends ActivityEmbeddingAnimationAdapter {
-        private final boolean mIsLeftHalf;
-        private final int mWholeAnimationWidth;
-
-        /**
-         * @param isLeftHalf whether this is the left half of the animation.
-         * @param wholeAnimationWidth the whole animation windows width.
-         */
-        SplitAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
-                boolean isLeftHalf, int wholeAnimationWidth) {
-            super(animation, change);
-            mIsLeftHalf = isLeftHalf;
-            mWholeAnimationWidth = wholeAnimationWidth;
-            if (wholeAnimationWidth == 0) {
-                throw new IllegalArgumentException("SplitAdapter must provide wholeAnimationWidth");
-            }
-        }
-
-        @Override
-        void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
-            final Point offset = mChange.getEndRelOffset();
-            float posX = offset.x;
-            final float posY = offset.y;
-            // This window is half of the whole animation window. Offset left/right to make it
-            // look as one with the other half.
-            mTransformation.getMatrix().getValues(mMatrix);
-            final int changeWidth = mChange.getEndAbsBounds().width();
-            final float scaleX = mMatrix[MSCALE_X];
-            final float totalOffset = mWholeAnimationWidth * (1 - scaleX) / 2;
-            final float curOffset = changeWidth * (1 - scaleX) / 2;
-            final float offsetDiff = totalOffset - curOffset;
-            if (mIsLeftHalf) {
-                posX += offsetDiff;
-            } else {
-                posX -= offsetDiff;
-            }
-            mTransformation.getMatrix().postTranslate(posX, posY);
-            t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
-            t.setAlpha(mLeash, mTransformation.getAlpha());
-        }
-    }
-
-    /**
      * Should be used for the animation of the snapshot of a {@link TransitionInfo.Change} that has
      * size change.
      */
@@ -181,7 +155,7 @@
 
         SnapshotAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
                 @NonNull SurfaceControl snapshotLeash) {
-            super(animation, change, snapshotLeash);
+            super(animation, change, snapshotLeash, change.getEndAbsBounds());
         }
 
         @Override
@@ -196,7 +170,9 @@
         void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
             super.onAnimationEnd(t);
             // Remove the screenshot leash after animation is finished.
-            t.remove(mLeash);
+            if (mLeash.isValid()) {
+                t.remove(mLeash);
+            }
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 7e0795d..d88cc00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -22,9 +22,9 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.animation.Animation;
@@ -40,6 +40,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.function.BiFunction;
 
 /** To run the ActivityEmbedding animations. */
@@ -169,15 +170,12 @@
         final Rect openingWholeScreenBounds = new Rect();
         final Rect closingWholeScreenBounds = new Rect();
         for (TransitionInfo.Change change : info.getChanges()) {
-            final Rect bounds = new Rect(change.getEndAbsBounds());
-            final Point offset = change.getEndRelOffset();
-            bounds.offsetTo(offset.x, offset.y);
             if (Transitions.isOpeningType(change.getMode())) {
                 openingChanges.add(change);
-                openingWholeScreenBounds.union(bounds);
+                openingWholeScreenBounds.union(change.getEndAbsBounds());
             } else {
                 closingChanges.add(change);
-                closingWholeScreenBounds.union(bounds);
+                closingWholeScreenBounds.union(change.getEndAbsBounds());
             }
         }
 
@@ -210,60 +208,73 @@
             @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
             @NonNull Rect wholeAnimationBounds) {
         final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
-        final Rect bounds = new Rect(change.getEndAbsBounds());
-        final Point offset = change.getEndRelOffset();
-        bounds.offsetTo(offset.x, offset.y);
-        if (bounds.left == wholeAnimationBounds.left
-                && bounds.right != wholeAnimationBounds.right) {
-            // This is the left split of the whole animation window.
-            return new ActivityEmbeddingAnimationAdapter.SplitAdapter(animation, change,
-                    true /* isLeftHalf */, wholeAnimationBounds.width());
-        } else if (bounds.left != wholeAnimationBounds.left
-                && bounds.right == wholeAnimationBounds.right) {
-            // This is the right split of the whole animation window.
-            return new ActivityEmbeddingAnimationAdapter.SplitAdapter(animation, change,
-                    false /* isLeftHalf */, wholeAnimationBounds.width());
-        }
-        // Open/close window that fills the whole animation.
-        return new ActivityEmbeddingAnimationAdapter(animation, change);
+        return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
+                wholeAnimationBounds);
     }
 
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createChangeAnimationAdapters(
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
         final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
+        final Set<TransitionInfo.Change> handledChanges = new ArraySet<>();
+
+        // For the first iteration, we prepare the animation for the change type windows. This is
+        // needed because there may be window that is reparented while resizing. In such case, we
+        // will do the following:
+        // 1. Capture a screenshot from the Activity surface.
+        // 2. Attach the screenshot surface to the top of TaskFragment (Activity's parent) surface.
+        // 3. Animate the TaskFragment using Activity Change info (start/end bounds).
+        // This is because the TaskFragment surface/change won't contain the Activity's before its
+        // reparent.
         for (TransitionInfo.Change change : info.getChanges()) {
-            if (change.getMode() == TRANSIT_CHANGE
-                    && !change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
-                // This is the window with bounds change.
-                final WindowContainerToken parentToken = change.getParent();
-                final Rect parentBounds;
-                if (parentToken != null) {
-                    TransitionInfo.Change parentChange = info.getChange(parentToken);
-                    parentBounds = parentChange != null
-                            ? parentChange.getEndAbsBounds()
-                            : change.getEndAbsBounds();
-                } else {
-                    parentBounds = change.getEndAbsBounds();
-                }
-                final Animation[] animations =
-                        mAnimationSpec.createChangeBoundsChangeAnimations(change, parentBounds);
-                // Adapter for the starting screenshot leash.
-                final SurfaceControl screenshotLeash = createScreenshot(change, startTransaction);
-                if (screenshotLeash != null) {
-                    // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
-                    adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
-                            animations[0], change, screenshotLeash));
-                } else {
-                    Log.e(TAG, "Failed to take screenshot for change=" + change);
-                }
-                // Adapter for the ending bounds changed leash.
-                adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
-                        animations[1], change));
+            if (change.getMode() != TRANSIT_CHANGE
+                    || change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
                 continue;
             }
 
-            // These are the other windows that don't have bounds change in the same transition.
+            // This is the window with bounds change.
+            handledChanges.add(change);
+            final WindowContainerToken parentToken = change.getParent();
+            TransitionInfo.Change boundsAnimationChange = change;
+            if (parentToken != null) {
+                // When the parent window is also included in the transition as an opening window,
+                // we would like to animate the parent window instead.
+                final TransitionInfo.Change parentChange = info.getChange(parentToken);
+                if (parentChange != null && Transitions.isOpeningType(parentChange.getMode())) {
+                    // We won't create a separate animation for the parent, but to animate the
+                    // parent for the child resizing.
+                    handledChanges.add(parentChange);
+                    boundsAnimationChange = parentChange;
+                }
+            }
+
+            final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
+                    boundsAnimationChange.getEndAbsBounds());
+
+            // Create a screenshot based on change, but attach it to the top of the
+            // boundsAnimationChange.
+            final SurfaceControl screenshotLeash = getOrCreateScreenshot(change,
+                    boundsAnimationChange, startTransaction);
+            if (screenshotLeash != null) {
+                // Adapter for the starting screenshot leash.
+                // The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
+                adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
+                        animations[0], change, screenshotLeash));
+            } else {
+                Log.e(TAG, "Failed to take screenshot for change=" + change);
+            }
+            // Adapter for the ending bounds changed leash.
+            adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
+                    animations[1], boundsAnimationChange));
+        }
+
+        // Handle the other windows that don't have bounds change in the same transition.
+        for (TransitionInfo.Change change : info.getChanges()) {
+            if (handledChanges.contains(change)) {
+                // Skip windows that we have already handled in the previous iteration.
+                continue;
+            }
+
             final Animation animation;
             if (!TransitionInfo.isIndependent(change, info)) {
                 // No-op if it will be covered by the changing parent window.
@@ -278,13 +289,27 @@
         return adapters;
     }
 
-    /** Takes a screenshot of the given {@link TransitionInfo.Change} surface. */
+    /**
+     * Takes a screenshot of the given {@code screenshotChange} surface if WM Core hasn't taken one.
+     * The screenshot leash should be attached to the {@code animationChange} surface which we will
+     * animate later.
+     */
     @Nullable
-    private SurfaceControl createScreenshot(@NonNull TransitionInfo.Change change,
-            @NonNull SurfaceControl.Transaction startTransaction) {
-        final Rect cropBounds = new Rect(change.getStartAbsBounds());
+    private SurfaceControl getOrCreateScreenshot(@NonNull TransitionInfo.Change screenshotChange,
+            @NonNull TransitionInfo.Change animationChange,
+            @NonNull SurfaceControl.Transaction t) {
+        final SurfaceControl screenshotLeash = screenshotChange.getSnapshot();
+        if (screenshotLeash != null) {
+            // If WM Core has already taken a screenshot, make sure it is reparented to the
+            // animation leash.
+            t.reparent(screenshotLeash, animationChange.getLeash());
+            return screenshotLeash;
+        }
+
+        // If WM Core hasn't taken a screenshot, take a screenshot now.
+        final Rect cropBounds = new Rect(screenshotChange.getStartAbsBounds());
         cropBounds.offsetTo(0, 0);
-        return ScreenshotUtils.takeScreenshot(startTransaction, change.getLeash(), cropBounds,
-                Integer.MAX_VALUE);
+        return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
+                animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index 6f06f28..ad0dddf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -185,8 +185,10 @@
         animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                 ? R.anim.task_fragment_open_enter
                 : R.anim.task_fragment_open_exit);
-        final Rect bounds = change.getEndAbsBounds();
-        animation.initialize(bounds.width(), bounds.height(),
+        // Use the whole animation bounds instead of the change bounds, so that when multiple change
+        // targets are opening at the same time, the animation applied to each will be the same.
+        // Otherwise, we may see gap between the activities that are launching together.
+        animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
                 wholeAnimationBounds.width(), wholeAnimationBounds.height());
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         return animation;
@@ -203,8 +205,10 @@
         animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                 ? R.anim.task_fragment_close_enter
                 : R.anim.task_fragment_close_exit);
-        final Rect bounds = change.getEndAbsBounds();
-        animation.initialize(bounds.width(), bounds.height(),
+        // Use the whole animation bounds instead of the change bounds, so that when multiple change
+        // targets are closing at the same time, the animation applied to each will be the same.
+        // Otherwise, we may see gap between the activities that are finishing together.
+        animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
                 wholeAnimationBounds.width(), wholeAnimationBounds.height());
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         return animation;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index e0004fc..521a65c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -16,7 +16,8 @@
 
 package com.android.wm.shell.activityembedding;
 
-import static android.window.TransitionInfo.FLAG_IS_EMBEDDED;
+import static android.window.TransitionInfo.FLAG_FILLS_TASK;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 
 import static java.util.Objects.requireNonNull;
 
@@ -84,12 +85,23 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        // TODO(b/207070762) Handle AE animation as a part of other transitions.
-        // Only handle the transition if all containers are embedded.
+        boolean containsEmbeddingSplit = false;
         for (TransitionInfo.Change change : info.getChanges()) {
-            if (!isEmbedded(change)) {
+            if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
+                // Only animate the transition if all changes are in a Task with ActivityEmbedding.
                 return false;
             }
+            if (!containsEmbeddingSplit && !change.hasFlags(FLAG_FILLS_TASK)) {
+                // Whether the Task contains any ActivityEmbedding split before or after the
+                // transition.
+                containsEmbeddingSplit = true;
+            }
+        }
+        if (!containsEmbeddingSplit) {
+            // Let the system to play the default animation if there is no ActivityEmbedding split
+            // window. This allows to play the app customized animation when there is no embedding,
+            // such as the device is in a folded state.
+            return false;
         }
 
         // Start ActivityEmbedding animation.
@@ -119,8 +131,4 @@
         }
         callback.onTransitionFinished(null /* wct */, null /* wctCB */);
     }
-
-    private static boolean isEmbedded(@NonNull TransitionInfo.Change change) {
-        return (change.getFlags() & FLAG_IS_EMBEDDED) != 0;
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 99b8885..b5a5754 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -170,7 +170,8 @@
     @VisibleForTesting(visibility = PRIVATE)
     public Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
             final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
-            int taskId, @Nullable final String locus, Executor mainExecutor) {
+            int taskId, @Nullable final String locus, Executor mainExecutor,
+            final Bubbles.BubbleMetadataFlagListener listener) {
         Objects.requireNonNull(key);
         Objects.requireNonNull(shortcutInfo);
         mMetadataShortcutId = shortcutInfo.getId();
@@ -188,11 +189,12 @@
         mShowBubbleUpdateDot = false;
         mMainExecutor = mainExecutor;
         mTaskId = taskId;
+        mBubbleMetadataFlagListener = listener;
     }
 
     @VisibleForTesting(visibility = PRIVATE)
     public Bubble(@NonNull final BubbleEntry entry,
-            @Nullable final Bubbles.BubbleMetadataFlagListener listener,
+            final Bubbles.BubbleMetadataFlagListener listener,
             final Bubbles.PendingIntentCanceledListener intentCancelListener,
             Executor mainExecutor) {
         mKey = entry.getKey();
@@ -830,6 +832,7 @@
         pw.print("  desiredHeight: "); pw.println(getDesiredHeightString());
         pw.print("  suppressNotif: "); pw.println(shouldSuppressNotification());
         pw.print("  autoExpand:    "); pw.println(shouldAutoExpand());
+        pw.print("  bubbleMetadataFlagListener null: " + (mBubbleMetadataFlagListener == null));
         if (mExpandedView != null) {
             mExpandedView.dump(pw);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index d63c25d..0dfba34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -309,6 +309,7 @@
     protected void onInit() {
         mBubbleData.setListener(mBubbleDataListener);
         mBubbleData.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged);
+        mDataRepository.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged);
 
         mBubbleData.setPendingIntentCancelledListener(bubble -> {
             if (bubble.getBubbleIntent() == null) {
@@ -1336,19 +1337,7 @@
                         }
                         mSysuiProxy.updateNotificationBubbleButton(bubble.getKey());
                     }
-
                 }
-                mSysuiProxy.getPendingOrActiveEntry(bubble.getKey(), (entry) -> {
-                    mMainExecutor.execute(() -> {
-                        if (entry != null) {
-                            final String groupKey = entry.getStatusBarNotification().getGroupKey();
-                            if (getBubblesInGroup(groupKey).isEmpty()) {
-                                // Time to potentially remove the summary
-                                mSysuiProxy.notifyMaybeCancelSummary(bubble.getKey());
-                            }
-                        }
-                    });
-                });
             }
             mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index c64133f..af31391 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -158,7 +158,6 @@
     @Nullable
     private Listener mListener;
 
-    @Nullable
     private Bubbles.BubbleMetadataFlagListener mBubbleMetadataFlagListener;
     private Bubbles.PendingIntentCanceledListener mCancelledListener;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 97560f4..3a59614 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -25,6 +25,7 @@
 import android.content.pm.UserInfo
 import android.os.UserHandle
 import android.util.Log
+import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener
 import com.android.wm.shell.bubbles.storage.BubbleEntity
 import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
 import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
@@ -47,6 +48,13 @@
     private val ioScope = CoroutineScope(Dispatchers.IO)
     private var job: Job? = null
 
+    // For use in Bubble construction.
+    private lateinit var bubbleMetadataFlagListener: BubbleMetadataFlagListener
+
+    fun setSuppressionChangedListener(listener: BubbleMetadataFlagListener) {
+        bubbleMetadataFlagListener = listener
+    }
+
     /**
      * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
      * asynchronously.
@@ -197,7 +205,8 @@
                                 entity.title,
                                 entity.taskId,
                                 entity.locus,
-                                mainExecutor
+                                mainExecutor,
+                                bubbleMetadataFlagListener
                         )
                     }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index cfbe1b3..54c91dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -53,13 +53,13 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
-import android.view.SurfaceControl;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
+import android.window.ScreenCapture;
 
 import androidx.annotation.Nullable;
 
@@ -508,7 +508,7 @@
 
     /** Return a GraphicBuffer with the contents of the task view surface. */
     @Nullable
-    SurfaceControl.ScreenshotHardwareBuffer snapshotActivitySurface() {
+    ScreenCapture.ScreenshotHardwareBuffer snapshotActivitySurface() {
         if (mIsOverflow) {
             // For now, just snapshot the view and return it as a hw buffer so that the animation
             // code for both the tasks and overflow can be the same
@@ -517,7 +517,7 @@
                     p.beginRecording(mOverflowView.getWidth(), mOverflowView.getHeight()));
             p.endRecording();
             Bitmap snapshot = Bitmap.createBitmap(p);
-            return new SurfaceControl.ScreenshotHardwareBuffer(
+            return new ScreenCapture.ScreenshotHardwareBuffer(
                     snapshot.getHardwareBuffer(),
                     snapshot.getColorSpace(),
                     false /* containsSecureLayers */,
@@ -526,7 +526,7 @@
         if (mTaskView == null || mTaskView.getSurfaceControl() == null) {
             return null;
         }
-        return SurfaceControl.captureLayers(
+        return ScreenCapture.captureLayers(
                 mTaskView.getSurfaceControl(),
                 new Rect(0, 0, mTaskView.getWidth(), mTaskView.getHeight()),
                 1 /* scale */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index aeaf6ed..2d9c2a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -51,7 +51,6 @@
 import android.view.Choreographer;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
@@ -64,6 +63,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
+import android.window.ScreenCapture;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -244,7 +244,7 @@
      * Buffer containing a screenshot of the animating-out bubble. This is drawn into the
      * SurfaceView during animations.
      */
-    private SurfaceControl.ScreenshotHardwareBuffer mAnimatingOutBubbleBuffer;
+    private ScreenCapture.ScreenshotHardwareBuffer mAnimatingOutBubbleBuffer;
 
     private BubbleFlyoutView mFlyout;
     /** Runnable that fades out the flyout and then sets it to GONE. */
@@ -1270,7 +1270,7 @@
         }
         final boolean seen = getPrefBoolean(ManageEducationViewKt.PREF_MANAGED_EDUCATION);
         final boolean shouldShow = (!seen || BubbleDebugConfig.forceShowUserEducation(mContext))
-                && mExpandedBubble != null;
+                && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null;
         if (BubbleDebugConfig.DEBUG_USER_EDUCATION) {
             Log.d(TAG, "Show manage edu: " + shouldShow);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 453b34e..b3104b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -276,8 +276,6 @@
 
         void notifyInvalidateNotifications(String reason);
 
-        void notifyMaybeCancelSummary(String key);
-
         void updateNotificationBubbleButton(String key);
 
         void onStackExpandChanged(boolean shouldExpand);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
index 063dac3..ab194df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
@@ -24,8 +24,8 @@
 import android.view.Gravity
 import android.view.View
 import android.view.ViewGroup
-import android.view.WindowManager
 import android.view.WindowInsets
+import android.view.WindowManager
 import android.widget.FrameLayout
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
@@ -41,6 +41,7 @@
 
     var circle = DismissCircleView(context)
     var isShowing = false
+    var targetSizeResId: Int
 
     private val animator = PhysicsAnimator.getInstance(circle)
     private val spring = PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY)
@@ -70,7 +71,8 @@
         setVisibility(View.INVISIBLE)
         setBackgroundDrawable(gradientDrawable)
 
-        val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
+        targetSizeResId = R.dimen.dismiss_circle_size
+        val targetSize: Int = resources.getDimensionPixelSize(targetSizeResId)
         addView(circle, LayoutParams(targetSize, targetSize,
                 Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL))
         // start with circle offscreen so it's animated up
@@ -126,7 +128,7 @@
         layoutParams.height = resources.getDimensionPixelSize(
                 R.dimen.floating_dismiss_gradient_height)
 
-        val targetSize: Int = resources.getDimensionPixelSize(R.dimen.dismiss_circle_size)
+        val targetSize = resources.getDimensionPixelSize(targetSizeResId)
         circle.layoutParams.width = targetSize
         circle.layoutParams.height = targetSize
         circle.requestLayout()
@@ -153,4 +155,4 @@
         setPadding(0, 0, 0, navInset.bottom +
                 resources.getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin))
     }
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 47f1e2e..96efeeb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -96,7 +96,8 @@
 
     /**
      * Different from {@link #equals(Object)}, this method compares the basic geometry properties
-     * of two {@link DisplayLayout} objects including width, height, rotation, density and cutout.
+     * of two {@link DisplayLayout} objects including width, height, rotation, density, cutout and
+     * insets.
      * @return {@code true} if the given {@link DisplayLayout} is identical geometry wise.
      */
     public boolean isSameGeometry(@NonNull DisplayLayout other) {
@@ -104,7 +105,8 @@
                 && mHeight == other.mHeight
                 && mRotation == other.mRotation
                 && mDensityDpi == other.mDensityDpi
-                && Objects.equals(mCutout, other.mCutout);
+                && Objects.equals(mCutout, other.mCutout)
+                && Objects.equals(mStableInsets, other.mStableInsets);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
index c4bd73b..fad3dee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
@@ -19,6 +19,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
+import android.window.ScreenCapture;
 
 import java.util.function.Consumer;
 
@@ -28,16 +29,16 @@
 public class ScreenshotUtils {
 
     /**
-     * Take a screenshot of the specified SurfaceControl.
+     * Takes a screenshot of the specified SurfaceControl.
      *
      * @param sc the SurfaceControl to take a screenshot of
      * @param crop the crop to use when capturing the screenshot
      * @param consumer Consumer for the captured buffer
      */
     public static void captureLayer(SurfaceControl sc, Rect crop,
-            Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
-        consumer.accept(SurfaceControl.captureLayers(
-                new SurfaceControl.LayerCaptureArgs.Builder(sc)
+            Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) {
+        consumer.accept(ScreenCapture.captureLayers(
+                new ScreenCapture.LayerCaptureArgs.Builder(sc)
                     .setSourceCrop(crop)
                     .setCaptureSecureLayers(true)
                     .setAllowProtected(true)
@@ -45,20 +46,23 @@
     }
 
     private static class BufferConsumer implements
-            Consumer<SurfaceControl.ScreenshotHardwareBuffer> {
+            Consumer<ScreenCapture.ScreenshotHardwareBuffer> {
         SurfaceControl mScreenshot = null;
         SurfaceControl.Transaction mTransaction;
         SurfaceControl mSurfaceControl;
+        SurfaceControl mParentSurfaceControl;
         int mLayer;
 
-        BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) {
+        BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, SurfaceControl parentSc,
+                int layer) {
             mTransaction = t;
             mSurfaceControl = sc;
+            mParentSurfaceControl = parentSc;
             mLayer = layer;
         }
 
         @Override
-        public void accept(SurfaceControl.ScreenshotHardwareBuffer buffer) {
+        public void accept(ScreenCapture.ScreenshotHardwareBuffer buffer) {
             if (buffer == null || buffer.getHardwareBuffer() == null) {
                 return;
             }
@@ -72,7 +76,7 @@
 
             mTransaction.setBuffer(mScreenshot, buffer.getHardwareBuffer());
             mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace());
-            mTransaction.reparent(mScreenshot, mSurfaceControl);
+            mTransaction.reparent(mScreenshot, mParentSurfaceControl);
             mTransaction.setLayer(mScreenshot, mLayer);
             mTransaction.show(mScreenshot);
             mTransaction.apply();
@@ -80,7 +84,7 @@
     }
 
     /**
-     * Take a screenshot of the specified SurfaceControl.
+     * Takes a screenshot of the specified SurfaceControl.
      *
      * @param t the transaction used to set changes on the resulting screenshot.
      * @param sc the SurfaceControl to take a screenshot of
@@ -91,7 +95,23 @@
      */
     public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
             Rect crop, int layer) {
-        BufferConsumer consumer = new BufferConsumer(t, sc, layer);
+        return takeScreenshot(t, sc, sc /* parentSc */, crop, layer);
+    }
+
+    /**
+     * Takes a screenshot of the specified SurfaceControl.
+     *
+     * @param t the transaction used to set changes on the resulting screenshot.
+     * @param sc the SurfaceControl to take a screenshot of
+     * @param parentSc  the SurfaceControl to attach the screenshot to.
+     * @param crop the crop to use when capturing the screenshot
+     * @param layer the layer to place the screenshot
+     *
+     * @return A SurfaceControl where the screenshot will be attached, or null if failed.
+     */
+    public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
+            SurfaceControl parentSc, Rect crop, int layer) {
+        BufferConsumer consumer = new BufferConsumer(t, sc, parentSc, layer);
         captureLayer(sc, crop, consumer);
         return consumer.mScreenshot;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 4c85d20..419e62d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -561,6 +561,10 @@
         if (from == to) {
             // No animation run, still callback to stop resizing.
             mSplitLayoutHandler.onLayoutSizeChanged(this);
+
+            if (flingFinishedCallback != null) {
+                flingFinishedCallback.run();
+            }
             InteractionJankMonitorUtils.endTracing(
                     CUJ_SPLIT_SCREEN_RESIZE);
             return;
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 b7656de..18ce364 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
@@ -82,7 +82,7 @@
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.SplitscreenPipMixedHandler;
+import com.android.wm.shell.transition.DefaultMixedHandler;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
 import com.android.wm.shell.unfold.UnfoldAnimationController;
@@ -220,13 +220,14 @@
             Context context,
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
+            Optional<RecentTasksController> recentTasksController,
             WindowDecorViewModel<?> windowDecorViewModel) {
         // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
         //                    override for this controller from the base module
         ShellInit init = FreeformComponents.isFreeformEnabled(context)
                 ? shellInit
                 : null;
-        return new FreeformTaskListener<>(init, shellTaskOrganizer,
+        return new FreeformTaskListener<>(init, shellTaskOrganizer, recentTasksController,
                 windowDecorViewModel);
     }
 
@@ -332,6 +333,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             @ShellMainThread ShellExecutor mainExecutor) {
         return Optional.ofNullable(PipController.create(
@@ -340,7 +342,7 @@
                 pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
                 pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                oneHandedController, mainExecutor));
+                displayInsetsController, oneHandedController, mainExecutor));
     }
 
     @WMSingleton
@@ -483,13 +485,13 @@
 
     @WMSingleton
     @Provides
-    static SplitscreenPipMixedHandler provideSplitscreenPipMixedHandler(
+    static DefaultMixedHandler provideDefaultMixedHandler(
             ShellInit shellInit,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             Transitions transitions) {
-        return new SplitscreenPipMixedHandler(shellInit, splitScreenOptional,
-                pipTouchHandlerOptional, transitions);
+        return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
+                pipTouchHandlerOptional);
     }
 
     //
@@ -618,7 +620,7 @@
     @ShellCreateTriggerOverride
     @Provides
     static Object provideIndependentShellComponentsToCreate(
-            SplitscreenPipMixedHandler splitscreenPipMixedHandler,
+            DefaultMixedHandler defaultMixedHandler,
             Optional<DesktopModeController> desktopModeController) {
         return new Object();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index 64cec2a..8993d54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -50,7 +50,7 @@
                     Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
             ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
             return result != 0;
-        } catch (Settings.SettingNotFoundException e) {
+        } catch (Exception e) {
             ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
             return false;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 4697a01..b59fe18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -258,12 +258,12 @@
                 break;
             case ACTION_DRAG_ENTERED:
                 pd.dragLayout.show();
-                pd.dragLayout.update(event);
                 break;
             case ACTION_DRAG_LOCATION:
                 pd.dragLayout.update(event);
                 break;
             case ACTION_DROP: {
+                pd.dragLayout.update(event);
                 return handleDrop(event, pd);
             }
             case ACTION_DRAG_EXITED: {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 8dcdda1..1baac71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -28,12 +28,15 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
 import java.io.PrintWriter;
+import java.util.Optional;
 
 /**
  * {@link ShellTaskOrganizer.TaskListener} for {@link
@@ -46,6 +49,7 @@
     private static final String TAG = "FreeformTaskListener";
 
     private final ShellTaskOrganizer mShellTaskOrganizer;
+    private final Optional<RecentTasksController> mRecentTasksOptional;
     private final WindowDecorViewModel<T> mWindowDecorationViewModel;
 
     private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -60,9 +64,11 @@
     public FreeformTaskListener(
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
+            Optional<RecentTasksController> recentTasksController,
             WindowDecorViewModel<T> windowDecorationViewModel) {
         mShellTaskOrganizer = shellTaskOrganizer;
         mWindowDecorationViewModel = windowDecorationViewModel;
+        mRecentTasksOptional = recentTasksController;
         if (shellInit != null) {
             shellInit.addInitCallback(this::onInit, this);
         }
@@ -83,6 +89,12 @@
                     mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
             t.apply();
         }
+
+        if (DesktopMode.IS_SUPPORTED && taskInfo.isVisible) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+                    "Adding active freeform task: #%d", taskInfo.taskId);
+            mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+        }
     }
 
     private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
@@ -111,6 +123,12 @@
                 taskInfo.taskId);
         mTasks.remove(taskInfo.taskId);
 
+        if (DesktopMode.IS_SUPPORTED) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+                    "Removing active freeform task: #%d", taskInfo.taskId);
+            mRecentTasksOptional.ifPresent(rt -> rt.removeActiveFreeformTask(taskInfo.taskId));
+        }
+
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             // Save window decorations of closing tasks so that we can hand them over to the
             // transition system if this method happens before the transition. In case where the
@@ -131,6 +149,14 @@
         if (state.mWindowDecoration != null) {
             mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
         }
+
+        if (DesktopMode.IS_SUPPORTED) {
+            if (taskInfo.isVisible) {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+                        "Adding active freeform task: #%d", taskInfo.taskId);
+                mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+            }
+        }
     }
 
     private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 297c79e..f170e77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -966,7 +966,7 @@
         // Re-set the PIP bounds to none.
         mPipBoundsState.setBounds(new Rect());
         mPipUiEventLoggerLogger.setTaskInfo(null);
-        mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0);
+        mPipMenuController.detach();
         mLeash = null;
 
         if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 6c9a6b6..3d879b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -49,6 +49,7 @@
 import android.util.Pair;
 import android.util.Size;
 import android.view.DisplayInfo;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.WindowManagerGlobal;
 import android.window.WindowContainerTransaction;
@@ -64,6 +65,7 @@
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
@@ -112,6 +114,9 @@
         UserChangeListener {
     private static final String TAG = "PipController";
 
+    private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
+            SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
+
     private boolean mEnablePipKeepClearAlgorithm =
             SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", false);
 
@@ -135,6 +140,7 @@
     private PipTransitionController mPipTransitionController;
     private TaskStackListenerImpl mTaskStackListener;
     private PipParamsChangedForwarder mPipParamsChangedForwarder;
+    private DisplayInsetsController mDisplayInsetsController;
     private Optional<OneHandedController> mOneHandedController;
     private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
@@ -143,6 +149,8 @@
     private final Rect mTmpInsetBounds = new Rect();
     private final int mEnterAnimationDuration;
 
+    private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback;
+
     private boolean mIsInFixedRotation;
     private PipAnimationListener mPinnedStackAnimationRecentsCallback;
 
@@ -274,14 +282,12 @@
                     if (mPipBoundsState.getDisplayId() == displayId) {
                         if (mEnablePipKeepClearAlgorithm) {
                             mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
-                            // only move if already in pip, other transitions account for keep clear
-                            // areas
-                            if (mPipTransitionState.hasEnteredPip()) {
-                                Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
-                                        mPipBoundsAlgorithm);
-                                mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
-                                        mEnterAnimationDuration, null);
-                            }
+
+                            mMainExecutor.removeCallbacks(
+                                    mMovePipInResponseToKeepClearAreasChangeCallback);
+                            mMainExecutor.executeDelayed(
+                                    mMovePipInResponseToKeepClearAreasChangeCallback,
+                                    PIP_KEEP_CLEAR_AREAS_DELAY);
                         }
                     }
                 }
@@ -338,6 +344,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor) {
         if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -351,7 +358,7 @@
                 pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
                 pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                oneHandedController, mainExecutor)
+                displayInsetsController, oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -374,6 +381,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor
     ) {
@@ -406,7 +414,17 @@
 
         mEnterAnimationDuration = mContext.getResources()
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
+        mMovePipInResponseToKeepClearAreasChangeCallback = () -> {
+            // only move if already in pip, other transitions account for keep clear areas
+            if (mPipTransitionState.hasEnteredPip()) {
+                Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
+                        mPipBoundsAlgorithm);
+                mPipTaskOrganizer.scheduleAnimateResizePip(destBounds,
+                        mEnterAnimationDuration, null);
+            }
+        };
         mPipParamsChangedForwarder = pipParamsChangedForwarder;
+        mDisplayInsetsController = displayInsetsController;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -549,6 +567,16 @@
                     }
                 });
 
+        mDisplayInsetsController.addInsetsChangedListener(mPipBoundsState.getDisplayId(),
+                new DisplayInsetsController.OnInsetsChangedListener() {
+                    @Override
+                    public void insetsChanged(InsetsState insetsState) {
+                        onDisplayChanged(
+                                mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()),
+                                false /* saveRestoreSnapFraction */);
+                    }
+                });
+
         mOneHandedController.ifPresent(controller -> {
             controller.registerTransitionCallback(
                     new OneHandedTransitionCallback() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java
new file mode 100644
index 0000000..acc0caf
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDoubleTapHelper.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.phone;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.graphics.Rect;
+
+import com.android.wm.shell.pip.PipBoundsState;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Static utilities to get appropriate {@link PipDoubleTapHelper.PipSizeSpec} on a double tap.
+ */
+public class PipDoubleTapHelper {
+
+    /**
+     * Should not be instantiated as a stateless class.
+     */
+    private PipDoubleTapHelper() {}
+
+    /**
+     * A constant that represents a pip screen size.
+     *
+     * <p>CUSTOM - user resized screen size (by pinching in/out)</p>
+     * <p>DEFAULT - normal screen size used as default when entering pip mode</p>
+     * <p>MAX - maximum allowed screen size</p>
+     */
+    @IntDef(value = {
+        SIZE_SPEC_CUSTOM,
+        SIZE_SPEC_DEFAULT,
+        SIZE_SPEC_MAX
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface PipSizeSpec {}
+
+    static final int SIZE_SPEC_CUSTOM = 2;
+    static final int SIZE_SPEC_DEFAULT = 0;
+    static final int SIZE_SPEC_MAX = 1;
+
+    /**
+     * Returns MAX or DEFAULT {@link PipSizeSpec} to toggle to/from.
+     *
+     * <p>Each double tap toggles back and forth between {@code PipSizeSpec.CUSTOM} and
+     * either {@code PipSizeSpec.MAX} or {@code PipSizeSpec.DEFAULT}. The choice between
+     * the latter two sizes is determined based on the current state of the pip screen.</p>
+     *
+     * @param mPipBoundsState current state of the pip screen
+     */
+    @PipSizeSpec
+    private static int getMaxOrDefaultPipSizeSpec(@NonNull PipBoundsState mPipBoundsState) {
+        // determine the average pip screen width
+        int averageWidth = (mPipBoundsState.getMaxSize().x
+                + mPipBoundsState.getMinSize().x) / 2;
+
+        // If pip screen width is above average, DEFAULT is the size spec we need to
+        // toggle to. Otherwise, we choose MAX.
+        return (mPipBoundsState.getBounds().width() > averageWidth)
+                ? SIZE_SPEC_DEFAULT
+                : SIZE_SPEC_MAX;
+    }
+
+    /**
+     * Determines the {@link PipSizeSpec} to toggle to on double tap.
+     *
+     * @param mPipBoundsState current state of the pip screen
+     * @param userResizeBounds latest user resized bounds (by pinching in/out)
+     * @return pip screen size to switch to
+     */
+    @PipSizeSpec
+    static int nextSizeSpec(@NonNull PipBoundsState mPipBoundsState,
+            @NonNull Rect userResizeBounds) {
+        // is pip screen at its maximum
+        boolean isScreenMax = mPipBoundsState.getBounds().width()
+                == mPipBoundsState.getMaxSize().x;
+
+        // is pip screen at its normal default size
+        boolean isScreenDefault = (mPipBoundsState.getBounds().width()
+                == mPipBoundsState.getNormalBounds().width())
+                && (mPipBoundsState.getBounds().height()
+                == mPipBoundsState.getNormalBounds().height());
+
+        // edge case 1
+        // if user hasn't resized screen yet, i.e. CUSTOM size does not exist yet
+        // or if user has resized exactly to DEFAULT, then we just want to maximize
+        if (isScreenDefault
+                && userResizeBounds.width() == mPipBoundsState.getNormalBounds().width()) {
+            return SIZE_SPEC_MAX;
+        }
+
+        // edge case 2
+        // if user has maximized, then we want to toggle to DEFAULT
+        if (isScreenMax
+                && userResizeBounds.width() == mPipBoundsState.getMaxSize().x) {
+            return SIZE_SPEC_DEFAULT;
+        }
+
+        // otherwise in general we want to toggle back to user's CUSTOM size
+        if (isScreenDefault || isScreenMax) {
+            return SIZE_SPEC_CUSTOM;
+        }
+
+        // if we are currently in user resized CUSTOM size state
+        // then we toggle either to MAX or DEFAULT depending on the current pip screen state
+        return getMaxOrDefaultPipSizeSpec(mPipBoundsState);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index a2fa058..84d9217 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -929,9 +929,18 @@
                     if (mMenuController.isMenuVisible()) {
                         mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
                     }
-                    if (toExpand) {
+
+                    // the size to toggle to after a double tap
+                    int nextSize = PipDoubleTapHelper
+                            .nextSizeSpec(mPipBoundsState, getUserResizeBounds());
+
+                    // actually toggle to the size chosen
+                    if (nextSize == PipDoubleTapHelper.SIZE_SPEC_MAX) {
                         mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
                         animateToMaximizedState(null);
+                    } else if (nextSize == PipDoubleTapHelper.SIZE_SPEC_DEFAULT) {
+                        mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
+                        animateToNormalSize(null);
                     } else {
                         animateToUnexpandedState(getUserResizeBounds());
                     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS
index 85441af..5aa3c4e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/OWNERS
@@ -1,2 +1,3 @@
 # WM shell sub-module TV pip owner
 galinap@google.com
+bronger@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 93c7529..3fef823 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -32,7 +32,7 @@
             Consts.TAG_WM_SHELL),
     WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
-    WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+    WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
     WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM_STARTING_WINDOW),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 7b42350..27bc1a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -43,6 +43,7 @@
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
@@ -52,6 +53,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
@@ -82,6 +84,15 @@
     private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();
 
     /**
+     * Set of taskId's that have been launched in freeform mode.
+     * This includes tasks that are currently running, visible and in freeform mode. And also
+     * includes tasks that are running in the background, are no longer visible, but at some point
+     * were visible to the user.
+     * This is used to decide which freeform apps belong to the user's desktop.
+     */
+    private final HashSet<Integer> mActiveFreeformTasks = new HashSet<>();
+
+    /**
      * Creates {@link RecentTasksController}, returns {@code null} if the feature is not
      * supported.
      */
@@ -206,6 +217,22 @@
         notifyRecentTasksChanged();
     }
 
+    /**
+     * Mark a task with given {@code taskId} as active in freeform
+     */
+    public void addActiveFreeformTask(int taskId) {
+        mActiveFreeformTasks.add(taskId);
+        notifyRecentTasksChanged();
+    }
+
+    /**
+     * Remove task with given {@code taskId} from active freeform tasks
+     */
+    public void removeActiveFreeformTask(int taskId) {
+        mActiveFreeformTasks.remove(taskId);
+        notifyRecentTasksChanged();
+    }
+
     @VisibleForTesting
     void notifyRecentTasksChanged() {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
@@ -273,6 +300,9 @@
             rawMapping.put(taskInfo.taskId, taskInfo);
         }
 
+        boolean desktopModeActive = DesktopMode.isActive(mContext);
+        ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>();
+
         // Pull out the pairs as we iterate back in the list
         ArrayList<GroupedRecentTaskInfo> recentTasks = new ArrayList<>();
         for (int i = 0; i < rawList.size(); i++) {
@@ -282,16 +312,31 @@
                 continue;
             }
 
+            if (desktopModeActive && mActiveFreeformTasks.contains(taskInfo.taskId)) {
+                // Freeform tasks will be added as a separate entry
+                freeformTasks.add(taskInfo);
+                continue;
+            }
+
             final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
-            if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
+            if (!desktopModeActive && pairedTaskId != INVALID_TASK_ID && rawMapping.contains(
+                    pairedTaskId)) {
                 final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
                 rawMapping.remove(pairedTaskId);
-                recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
+                recentTasks.add(GroupedRecentTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
                         mTaskSplitBoundsMap.get(pairedTaskId)));
             } else {
-                recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
+                recentTasks.add(GroupedRecentTaskInfo.forSingleTask(taskInfo));
             }
         }
+
+        // Add a special entry for freeform tasks
+        if (!freeformTasks.isEmpty()) {
+            // First task is added separately
+            recentTasks.add(0, GroupedRecentTaskInfo.forFreeformTasks(
+                    freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0])));
+        }
+
         return recentTasks;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 3714fe7..ecdafa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -21,6 +21,7 @@
 import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
 import android.os.UserHandle;
+import com.android.internal.logging.InstanceId;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.window.RemoteTransition;
@@ -67,34 +68,35 @@
      * Starts a shortcut in a stage.
      */
     oneway void startShortcut(String packageName, String shortcutId, int position,
-            in Bundle options, in UserHandle user) = 8;
+            in Bundle options, in UserHandle user, in InstanceId instanceId) = 8;
 
     /**
      * Starts an activity in a stage.
      */
     oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int position,
-            in Bundle options) = 9;
+            in Bundle options, in InstanceId instanceId) = 9;
 
     /**
      * Starts tasks simultaneously in one transition.
      */
     oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
             in Bundle sideOptions, int sidePosition, float splitRatio,
-            in RemoteTransition remoteTransition) = 10;
+            in RemoteTransition remoteTransition, in InstanceId instanceId) = 10;
 
     /**
      * Version of startTasks using legacy transition system.
      */
     oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
             int sideTaskId, in Bundle sideOptions, int sidePosition,
-            float splitRatio, in RemoteAnimationAdapter adapter) = 11;
+            float splitRatio, in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 11;
 
     /**
      * Starts a pair of intent and task using legacy transition system.
      */
     oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
             in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions,
-            int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter) = 12;
+            int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter,
+            in InstanceId instanceId) = 12;
 
     /**
      * Blocking call that notifies and gets additional split-screen targets when entering
@@ -115,5 +117,5 @@
      */
     oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo, int taskId,
             in Bundle mainOptions, in Bundle sideOptions, int sidePosition, float splitRatio,
-            in RemoteAnimationAdapter adapter) = 15;
+            in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 15;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index b0080b2..e7ec15e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -45,11 +45,6 @@
                 iconProvider);
     }
 
-    @Override
-    void dismiss(WindowContainerTransaction wct, boolean toTop) {
-        deactivate(wct, toTop);
-    }
-
     boolean isActive() {
         return mIsActive;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 86efbe0..8639b36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -42,11 +42,6 @@
                 iconProvider);
     }
 
-    @Override
-    void dismiss(WindowContainerTransaction wct, boolean toTop) {
-        removeAllTasks(wct, toTop);
-    }
-
     boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
         if (mChildrenTaskInfo.size() == 0) return false;
         wct.reparentTasks(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 8729161..025e559 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -147,7 +147,6 @@
     private final DragAndDropController mDragAndDropController;
     private final Transitions mTransitions;
     private final TransactionPool mTransactionPool;
-    private final SplitscreenEventLogger mLogger;
     private final IconProvider mIconProvider;
     private final Optional<RecentTasksController> mRecentTasksOptional;
     private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
@@ -186,7 +185,6 @@
         mDragAndDropController = dragAndDropController;
         mTransitions = transitions;
         mTransactionPool = transactionPool;
-        mLogger = new SplitscreenEventLogger();
         mIconProvider = iconProvider;
         mRecentTasksOptional = recentTasks;
         mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
@@ -221,7 +219,7 @@
     protected StageCoordinator createStageCoordinator() {
         return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                 mTaskOrganizer, mDisplayController, mDisplayImeController,
-                mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
+                mDisplayInsetsController, mTransitions, mTransactionPool,
                 mIconProvider, mMainExecutor, mRecentTasksOptional);
     }
 
@@ -389,6 +387,17 @@
         }
     }
 
+    /**
+     * See {@link #startShortcut(String, String, int, Bundle, UserHandle)}
+     * @param instanceId to be used by {@link SplitscreenEventLogger}
+     */
+    public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
+            @Nullable Bundle options, UserHandle user, @NonNull InstanceId instanceId) {
+        mStageCoordinator.getLogger().enterRequested(instanceId);
+        startShortcut(packageName, shortcutId, position, options, user);
+    }
+
+    @Override
     public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
             @Nullable Bundle options, UserHandle user) {
         IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@@ -417,7 +426,6 @@
                 0 /* duration */, 0 /* statusBarTransitionDelay */);
         ActivityOptions activityOptions = ActivityOptions.fromBundle(options);
         activityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
-
         try {
             LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
             launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
@@ -427,6 +435,17 @@
         }
     }
 
+    /**
+     * See {@link #startIntent(PendingIntent, Intent, int, Bundle)}
+     * @param instanceId to be used by {@link SplitscreenEventLogger}
+     */
+    public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
+            @SplitPosition int position, @Nullable Bundle options, @NonNull InstanceId instanceId) {
+        mStageCoordinator.getLogger().enterRequested(instanceId);
+        startIntent(intent, fillInIntent, position, options);
+    }
+
+    @Override
     public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
             @SplitPosition int position, @Nullable Bundle options) {
         if (fillInIntent == null) {
@@ -448,7 +467,6 @@
             mStageCoordinator.startIntentLegacy(intent, fillInIntent, position, options);
             return;
         }
-
         mStageCoordinator.startIntent(intent, fillInIntent, position, options);
     }
 
@@ -774,60 +792,64 @@
         @Override
         public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
                 int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
-                float splitRatio, RemoteAnimationAdapter adapter) {
+                float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController, "startTasks",
                     (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(
                             mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,
-                            splitRatio, adapter));
+                            splitRatio, adapter, instanceId));
         }
 
         @Override
         public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
                 Intent fillInIntent, int taskId, Bundle mainOptions, Bundle sideOptions,
-                int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+                int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+                InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController,
                     "startIntentAndTaskWithLegacyTransition", (controller) ->
                             controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
                                     pendingIntent, fillInIntent, taskId, mainOptions, sideOptions,
-                                    sidePosition, splitRatio, adapter));
+                                    sidePosition, splitRatio, adapter, instanceId));
         }
 
         @Override
         public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
                 int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
-                @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+                @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+                InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController,
                     "startShortcutAndTaskWithLegacyTransition", (controller) ->
                             controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition(
                                     shortcutInfo, taskId, mainOptions, sideOptions, sidePosition,
-                                    splitRatio, adapter));
+                                    splitRatio, adapter, instanceId));
         }
 
         @Override
         public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
                 int sideTaskId, @Nullable Bundle sideOptions,
                 @SplitPosition int sidePosition, float splitRatio,
-                @Nullable RemoteTransition remoteTransition) {
+                @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController, "startTasks",
                     (controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
-                            sideTaskId, sideOptions, sidePosition, splitRatio, remoteTransition));
+                            sideTaskId, sideOptions, sidePosition, splitRatio, remoteTransition,
+                            instanceId));
         }
 
         @Override
         public void startShortcut(String packageName, String shortcutId, int position,
-                @Nullable Bundle options, UserHandle user) {
+                @Nullable Bundle options, UserHandle user, InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController, "startShortcut",
                     (controller) -> {
-                        controller.startShortcut(packageName, shortcutId, position, options, user);
+                        controller.startShortcut(packageName, shortcutId, position, options, user,
+                                instanceId);
                     });
         }
 
         @Override
         public void startIntent(PendingIntent intent, Intent fillInIntent, int position,
-                @Nullable Bundle options) {
+                @Nullable Bundle options, InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController, "startIntent",
                     (controller) -> {
-                        controller.startIntent(intent, fillInIntent, position, options);
+                        controller.startIntent(intent, fillInIntent, position, options, instanceId);
                     });
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index 3e7a100..626ccb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -16,7 +16,7 @@
 
 package com.android.wm.shell.splitscreen;
 
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
 import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
 import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
 import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
@@ -59,7 +59,7 @@
 
     // Drag info
     private @SplitPosition int mDragEnterPosition;
-    private InstanceId mDragEnterSessionId;
+    private InstanceId mEnterSessionId;
 
     // For deduping async events
     private int mLastMainStagePosition = -1;
@@ -82,9 +82,17 @@
     /**
      * May be called before logEnter() to indicate that the session was started from a drag.
      */
-    public void enterRequestedByDrag(@SplitPosition int position, InstanceId dragSessionId) {
+    public void enterRequestedByDrag(@SplitPosition int position, InstanceId enterSessionId) {
         mDragEnterPosition = position;
-        mDragEnterSessionId = dragSessionId;
+        enterRequested(enterSessionId);
+    }
+
+    /**
+     * May be called before logEnter() to indicate that the session was started from launcher.
+     * This specifically is for all the scenarios where split started without a drag interaction
+     */
+    public void enterRequested(InstanceId enterSessionId) {
+        mEnterSessionId = enterSessionId;
     }
 
     /**
@@ -97,7 +105,7 @@
         mLoggerSessionId = mIdSequence.newInstanceId();
         int enterReason = mDragEnterPosition != SPLIT_POSITION_UNDEFINED
                 ? getDragEnterReasonFromSplitPosition(mDragEnterPosition, isLandscape)
-                : SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+                : SPLITSCREEN_UICHANGED__ENTER_REASON__LAUNCHER;
         updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
                 mainStageUid);
         updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
@@ -112,7 +120,7 @@
                 mLastMainStageUid,
                 mLastSideStagePosition,
                 mLastSideStageUid,
-                mDragEnterSessionId != null ? mDragEnterSessionId.getId() : 0,
+                mEnterSessionId != null ? mEnterSessionId.getId() : 0,
                 mLoggerSessionId.getId());
     }
 
@@ -176,7 +184,7 @@
         // Reset states
         mLoggerSessionId = null;
         mDragEnterPosition = SPLIT_POSITION_UNDEFINED;
-        mDragEnterSessionId = null;
+        mEnterSessionId = null;
         mLastMainStagePosition = -1;
         mLastMainStageUid = -1;
         mLastSideStagePosition = -1;
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 fbbc6d3..db35b48 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
@@ -69,6 +69,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityOptions;
 import android.app.IActivityTaskManager;
 import android.app.PendingIntent;
 import android.app.WindowConfiguration;
@@ -87,6 +88,7 @@
 import android.util.Slog;
 import android.view.Choreographer;
 import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
@@ -121,6 +123,7 @@
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
+import com.android.wm.shell.transition.DefaultMixedHandler;
 import com.android.wm.shell.transition.LegacyTransitions;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.util.SplitBounds;
@@ -201,6 +204,8 @@
     @StageType
     private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
 
+    private DefaultMixedHandler mMixedHandler;
+
     private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
             new SplitWindowManager.ParentContainerCallbacks() {
                 @Override
@@ -250,14 +255,14 @@
             ShellTaskOrganizer taskOrganizer, DisplayController displayController,
             DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, Transitions transitions,
-            TransactionPool transactionPool, SplitscreenEventLogger logger,
+            TransactionPool transactionPool,
             IconProvider iconProvider, ShellExecutor mainExecutor,
             Optional<RecentTasksController> recentTasks) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
         mTaskOrganizer = taskOrganizer;
-        mLogger = logger;
+        mLogger = new SplitscreenEventLogger();
         mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
 
@@ -301,7 +306,7 @@
             DisplayController displayController, DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
             Transitions transitions, TransactionPool transactionPool,
-            SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+            ShellExecutor mainExecutor,
             Optional<RecentTasksController> recentTasks) {
         mContext = context;
         mDisplayId = displayId;
@@ -316,7 +321,7 @@
         mSplitLayout = splitLayout;
         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                 this::onTransitionAnimationComplete, this);
-        mLogger = logger;
+        mLogger = new SplitscreenEventLogger();
         mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
         mDisplayController.addDisplayWindowListener(this);
@@ -324,6 +329,10 @@
         transitions.addHandler(this);
     }
 
+    public void setMixedHandler(DefaultMixedHandler mixedHandler) {
+        mMixedHandler = mixedHandler;
+    }
+
     @VisibleForTesting
     SplitScreenTransitions getSplitTransitions() {
         return mSplitTransitions;
@@ -405,6 +414,10 @@
         return result;
     }
 
+    SplitscreenEventLogger getLogger() {
+        return mLogger;
+    }
+
     /** Launches an activity into split. */
     void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
             @Nullable Bundle options) {
@@ -497,7 +510,7 @@
     /** Starts 2 tasks in one transition. */
     void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
             @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
-            @Nullable RemoteTransition remoteTransition) {
+            @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         mainOptions = mainOptions != null ? mainOptions : new Bundle();
         sideOptions = sideOptions != null ? sideOptions : new Bundle();
@@ -526,46 +539,57 @@
 
         mSplitTransitions.startEnterTransition(
                 TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null);
+        setEnterInstanceId(instanceId);
     }
 
     /** Starts 2 tasks in one legacy transition. */
     void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
             int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
-            float splitRatio, RemoteAnimationAdapter adapter) {
+            float splitRatio, RemoteAnimationAdapter adapter,
+            InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (sideOptions == null) sideOptions = new Bundle();
         addActivityOptions(sideOptions, mSideStage);
         wct.startTask(sideTaskId, sideOptions);
 
-        startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter);
+        startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter,
+                instanceId);
     }
 
     /** Start an intent and a task ordered by {@code intentFirst}. */
     void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
             int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
-            @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+            @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+            InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (sideOptions == null) sideOptions = new Bundle();
         addActivityOptions(sideOptions, mSideStage);
         wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
 
-        startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter);
+        startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter,
+                instanceId);
     }
 
     void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
             int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
-            @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+            @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+            InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         if (sideOptions == null) sideOptions = new Bundle();
         addActivityOptions(sideOptions, mSideStage);
         wct.startShortcut(mContext.getPackageName(), shortcutInfo, sideOptions);
 
-        startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter);
+        startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter,
+                instanceId);
     }
 
-    private void startWithLegacyTransition(WindowContainerTransaction sideWct, int mainTaskId,
+    /**
+     * @param instanceId if {@code null}, will not log. Otherwise it will be used in
+     *                   {@link SplitscreenEventLogger#logEnter(float, int, int, int, int, boolean)}
+     */
+    private void startWithLegacyTransition(WindowContainerTransaction wct, int mainTaskId,
             @Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio,
-            RemoteAnimationAdapter adapter) {
+            RemoteAnimationAdapter adapter, InstanceId instanceId) {
         // Init divider first to make divider leash for remote animation target.
         mSplitLayout.init();
         mSplitLayout.setDivideRatio(splitRatio);
@@ -574,57 +598,56 @@
         mShouldUpdateRecents = false;
         mIsDividerRemoteAnimating = true;
 
-        LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
+        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
+        prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
+
+        IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
             @Override
-            public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
-                    RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
-                    IRemoteAnimationFinishedCallback finishedCallback,
-                    SurfaceControl.Transaction t) {
-                if (apps == null || apps.length == 0) {
-                    onRemoteAnimationFinished(apps);
-                    t.apply();
-                    try {
-                        adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Error starting remote animation", e);
-                    }
-                    return;
-                }
-
-                // Wrap the divider bar into non-apps target to animate together.
-                nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
-                        getDividerBarLegacyTarget());
-
-                updateSurfaceBounds(mSplitLayout, t, false);
-                setDividerVisibility(true, t);
-                for (int i = 0; i < apps.length; ++i) {
-                    if (apps[i].mode == MODE_OPENING) {
-                        t.show(apps[i].leash);
-                        // Reset the surface position of the opening app to prevent double-offset.
-                        t.setPosition(apps[i].leash, 0, 0);
-                    }
-                }
-                t.apply();
-
+            public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+                    RemoteAnimationTarget[] apps,
+                    RemoteAnimationTarget[] wallpapers,
+                    RemoteAnimationTarget[] nonApps,
+                    final IRemoteAnimationFinishedCallback finishedCallback) {
                 IRemoteAnimationFinishedCallback wrapCallback =
                         new IRemoteAnimationFinishedCallback.Stub() {
                             @Override
                             public void onAnimationFinished() throws RemoteException {
-                                onRemoteAnimationFinished(apps);
+                                onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct);
                                 finishedCallback.onAnimationFinished();
                             }
                         };
                 Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication());
                 try {
-                    adapter.getRunner().onAnimationStart(
-                            transit, apps, wallpapers, nonApps, wrapCallback);
+                    adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
+                            ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
+                                    getDividerBarLegacyTarget()), wrapCallback);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error starting remote animation", e);
+                }
+            }
+
+            @Override
+            public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                onRemoteAnimationFinishedOrCancelled(true /* cancel */, evictWct);
+                try {
+                    adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error starting remote animation", e);
                 }
             }
         };
+        RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
+                wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
 
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        if (mainOptions == null) {
+            mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
+        } else {
+            ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
+            mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+            mainOptions = mainActivityOptions.toBundle();
+        }
+
         setSideStagePosition(sidePosition, wct);
         if (!mMainStage.isActive()) {
             mMainStage.activate(wct, false /* reparent */);
@@ -632,34 +655,40 @@
 
         if (mainOptions == null) mainOptions = new Bundle();
         addActivityOptions(mainOptions, mMainStage);
-        wct.startTask(mainTaskId, mainOptions);
-        wct.merge(sideWct, true);
-
         updateWindowBounds(mSplitLayout, wct);
+        wct.startTask(mainTaskId, mainOptions);
         wct.reorder(mRootTaskInfo.token, true);
         wct.setForceTranslucent(mRootTaskInfo.token, false);
 
-        mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
+        mSyncQueue.queue(wct);
+        mSyncQueue.runInSync(t -> {
+            setDividerVisibility(true, t);
+            updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+        });
+
+        setEnterInstanceId(instanceId);
     }
 
-    private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
+    private void setEnterInstanceId(InstanceId instanceId) {
+        if (instanceId != null) {
+            mLogger.enterRequested(instanceId);
+        }
+    }
+
+    private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
+            WindowContainerTransaction evictWct) {
         mIsDividerRemoteAnimating = false;
         mShouldUpdateRecents = true;
-        if (apps == null || apps.length == 0) return;
-
-        // If any stage has no child after finished animation, that side of the split will display
-        // nothing. This might happen if starting the same app on the both sides while not
-        // supporting multi-instance. Exit the split screen and expand that app to full screen.
-        if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
-            mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0
-                    ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
-            return;
+        // If any stage has no child after animation finished, it means that split will display
+        // nothing, such status will happen if task and intent is same app but not support
+        // multi-instance, we should exit split and expand that app as full screen.
+        if (!cancel && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) {
+            mMainExecutor.execute(() ->
+                    exitSplitScreen(mMainStage.getChildCount() == 0
+                            ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
+        } else {
+            mSyncQueue.queue(evictWct);
         }
-
-        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
-        prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
-        prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
-        mSyncQueue.queue(evictWct);
     }
 
     /**
@@ -905,13 +934,10 @@
             // Expand to top side split as full screen for fading out decor animation and dismiss
             // another side split(Moving its children to bottom).
             mIsExiting = true;
-            final StageTaskListener tempFullStage = childrenToTop;
-            final StageTaskListener dismissStage = mMainStage == childrenToTop
-                    ? mSideStage : mMainStage;
-            tempFullStage.resetBounds(wct);
-            wct.setSmallestScreenWidthDp(tempFullStage.mRootTaskInfo.token,
+            childrenToTop.resetBounds(wct);
+            wct.reorder(childrenToTop.mRootTaskInfo.token, true);
+            wct.setSmallestScreenWidthDp(childrenToTop.mRootTaskInfo.token,
                     SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
-            dismissStage.dismiss(wct, false /* toTop */);
         }
         mSyncQueue.queue(wct);
         mSyncQueue.runInSync(t -> {
@@ -928,7 +954,8 @@
                 childrenToTop.fadeOutDecor(() -> {
                     WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
                     mIsExiting = false;
-                    childrenToTop.dismiss(finishedWCT, true /* toTop */);
+                    mMainStage.deactivate(finishedWCT, childrenToTop == mMainStage /* toTop */);
+                    mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */);
                     finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
                     finishedWCT.setForceTranslucent(mRootTaskInfo.token, true);
                     finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
@@ -1857,8 +1884,25 @@
 
             // Use normal animations.
             return false;
+        } else if (mMixedHandler != null && hasDisplayChange(info)) {
+            // A display-change has been un-expectedly inserted into the transition. Redirect
+            // handling to the mixed-handler to deal with splitting it up.
+            if (mMixedHandler.animatePendingSplitWithDisplayChange(transition, info,
+                    startTransaction, finishTransaction, finishCallback)) {
+                return true;
+            }
         }
 
+        return startPendingAnimation(transition, info, startTransaction, finishTransaction,
+                finishCallback);
+    }
+
+    /** Starts the pending transition animation. */
+    public boolean startPendingAnimation(@NonNull IBinder transition,
+            @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
         boolean shouldAnimate = true;
         if (mSplitTransitions.isPendingEnter(transition)) {
             shouldAnimate = startPendingEnterAnimation(
@@ -1877,6 +1921,15 @@
         return true;
     }
 
+    private boolean hasDisplayChange(TransitionInfo info) {
+        boolean has = false;
+        for (int iC = 0; iC < info.getChanges().size() && !has; ++iC) {
+            final TransitionInfo.Change change = info.getChanges().get(iC);
+            has = change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_IS_DISPLAY) != 0;
+        }
+        return has;
+    }
+
     /** Called to clean-up state and do house-keeping after the animation is done. */
     public void onTransitionAnimationComplete() {
         // If still playing, let it finish.
@@ -1885,7 +1938,6 @@
             // properly for the animation itself.
             mSplitLayout.release();
             mSplitLayout.resetDividerPosition();
-            mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
             mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 1af9415..6b90eab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -106,11 +106,6 @@
         taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
     }
 
-    /**
-     * General function for dismiss this stage.
-     */
-    void dismiss(WindowContainerTransaction wct, boolean toTop) {}
-
     int getChildCount() {
         return mChildrenTaskInfo.size();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS
index d325d16..28be0ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/OWNERS
@@ -1,2 +1,3 @@
 # WM shell sub-module TV splitscreen owner
 galinap@google.com
+bronger@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
index 9285e84..46d2a5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
@@ -34,7 +34,6 @@
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.splitscreen.SplitscreenEventLogger;
 import com.android.wm.shell.splitscreen.StageCoordinator;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
@@ -111,7 +110,7 @@
         return new TvStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                 mTaskOrganizer, mDisplayController, mDisplayImeController,
                 mDisplayInsetsController, mTransitions, mTransactionPool,
-                new SplitscreenEventLogger(), mIconProvider, mMainExecutor, mMainHandler,
+                mIconProvider, mMainExecutor, mMainHandler,
                 mRecentTasksOptional, mSystemWindows);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
index 6595beb..4d563fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
@@ -30,7 +30,6 @@
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.split.SplitScreenConstants;
 import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.splitscreen.SplitscreenEventLogger;
 import com.android.wm.shell.splitscreen.StageCoordinator;
 import com.android.wm.shell.transition.Transitions;
 
@@ -48,13 +47,13 @@
             ShellTaskOrganizer taskOrganizer, DisplayController displayController,
             DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, Transitions transitions,
-            TransactionPool transactionPool, SplitscreenEventLogger logger,
+            TransactionPool transactionPool,
             IconProvider iconProvider, ShellExecutor mainExecutor,
             Handler mainHandler,
             Optional<RecentTasksController> recentTasks,
             SystemWindows systemWindows) {
         super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController,
-                displayInsetsController, transitions, transactionPool, logger, iconProvider,
+                displayInsetsController, transitions, transactionPool, iconProvider,
                 mainExecutor, recentTasks);
 
         mTvSplitMenuController = new TvSplitMenuController(context, this,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index e26c259..3cba929 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.transition;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 
@@ -35,10 +36,14 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.splitscreen.StageCoordinator;
+import com.android.wm.shell.sysui.ShellInit;
 
 import java.util.ArrayList;
+import java.util.Optional;
 
 /**
  * A handler for dealing with transitions involving multiple other handlers. For example: an
@@ -47,12 +52,15 @@
 public class DefaultMixedHandler implements Transitions.TransitionHandler {
 
     private final Transitions mPlayer;
-    private final PipTransitionController mPipHandler;
-    private final StageCoordinator mSplitHandler;
+    private PipTransitionController mPipHandler;
+    private StageCoordinator mSplitHandler;
 
     private static class MixedTransition {
         static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
 
+        /** Both the display and split-state (enter/exit) is changing */
+        static final int TYPE_DISPLAY_AND_SPLIT_CHANGE = 2;
+
         /** The default animation for this mixed transition. */
         static final int ANIM_TYPE_DEFAULT = 0;
 
@@ -65,6 +73,7 @@
 
         Transitions.TransitionFinishCallback mFinishCallback = null;
         Transitions.TransitionHandler mLeftoversHandler = null;
+        WindowContainerTransaction mFinishWCT = null;
 
         /**
          * Mixed transitions are made up of multiple "parts". This keeps track of how many
@@ -77,13 +86,25 @@
             mTransition = transition;
         }
     }
+
     private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
 
-    public DefaultMixedHandler(@NonNull Transitions player,
-            @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+    public DefaultMixedHandler(@NonNull ShellInit shellInit, @NonNull Transitions player,
+            Optional<SplitScreenController> splitScreenControllerOptional,
+            Optional<PipTouchHandler> pipTouchHandlerOptional) {
         mPlayer = player;
-        mPipHandler = pipHandler;
-        mSplitHandler = splitHandler;
+        if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
+                && splitScreenControllerOptional.isPresent()) {
+            // Add after dependencies because it is higher priority
+            shellInit.addInitCallback(() -> {
+                mPipHandler = pipTouchHandlerOptional.get().getTransitionHandler();
+                mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler();
+                mPlayer.addHandler(this);
+                if (mSplitHandler != null) {
+                    mSplitHandler.setMixedHandler(this);
+                }
+            }, this);
+        }
     }
 
     @Nullable
@@ -109,10 +130,12 @@
     }
 
     private TransitionInfo subCopy(@NonNull TransitionInfo info,
-            @WindowManager.TransitionType int newType) {
-        final TransitionInfo out = new TransitionInfo(newType, info.getFlags());
-        for (int i = 0; i < info.getChanges().size(); ++i) {
-            out.getChanges().add(info.getChanges().get(i));
+            @WindowManager.TransitionType int newType, boolean withChanges) {
+        final TransitionInfo out = new TransitionInfo(newType, withChanges ? info.getFlags() : 0);
+        if (withChanges) {
+            for (int i = 0; i < info.getChanges().size(); ++i) {
+                out.getChanges().add(info.getChanges().get(i));
+            }
         }
         out.setRootLeash(info.getRootLeash(), info.getRootOffset().x, info.getRootOffset().y);
         out.setAnimationOptions(info.getAnimationOptions());
@@ -144,6 +167,8 @@
         if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) {
             return animateEnterPipFromSplit(mixed, info, startTransaction, finishTransaction,
                     finishCallback);
+        } else if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) {
+            return false;
         } else {
             mActiveTransitions.remove(mixed);
             throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -160,7 +185,7 @@
                 + "entering PIP while Split-Screen is active.");
         TransitionInfo.Change pipChange = null;
         TransitionInfo.Change wallpaper = null;
-        final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK);
+        final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK, true /* changes */);
         boolean homeIsOpening = false;
         for (int i = info.getChanges().size() - 1; i >= 0; --i) {
             TransitionInfo.Change change = info.getChanges().get(i);
@@ -241,6 +266,87 @@
         return true;
     }
 
+    private void unlinkMissingParents(TransitionInfo from) {
+        for (int i = 0; i < from.getChanges().size(); ++i) {
+            final TransitionInfo.Change chg = from.getChanges().get(i);
+            if (chg.getParent() == null) continue;
+            if (from.getChange(chg.getParent()) == null) {
+                from.getChanges().get(i).setParent(null);
+            }
+        }
+    }
+
+    private boolean isWithinTask(TransitionInfo info, TransitionInfo.Change chg) {
+        TransitionInfo.Change curr = chg;
+        while (curr != null) {
+            if (curr.getTaskInfo() != null) return true;
+            if (curr.getParent() == null) break;
+            curr = info.getChange(curr.getParent());
+        }
+        return false;
+    }
+
+    /**
+     * This is intended to be called by SplitCoordinator as a helper to mix an already-pending
+     * split transition with a display-change. The use-case for this is when a display
+     * change/rotation gets collected into a split-screen enter/exit transition which has already
+     * been claimed by StageCoordinator.handleRequest . This happens during launcher tests.
+     */
+    public boolean animatePendingSplitWithDisplayChange(@NonNull IBinder transition,
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT,
+            @NonNull SurfaceControl.Transaction finishT,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        final TransitionInfo everythingElse = subCopy(info, info.getType(), true /* withChanges */);
+        final TransitionInfo displayPart = subCopy(info, TRANSIT_CHANGE, false /* withChanges */);
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            TransitionInfo.Change change = info.getChanges().get(i);
+            if (isWithinTask(info, change)) continue;
+            displayPart.addChange(change);
+            everythingElse.getChanges().remove(i);
+        }
+        if (displayPart.getChanges().isEmpty()) return false;
+        unlinkMissingParents(everythingElse);
+        final MixedTransition mixed = new MixedTransition(
+                MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE, transition);
+        mixed.mFinishCallback = finishCallback;
+        mActiveTransitions.add(mixed);
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is a mix of display change "
+                + "and split change.");
+        // We need to split the transition into 2 parts: the split part and the display part.
+        mixed.mInFlightSubAnimations = 2;
+
+        Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+            --mixed.mInFlightSubAnimations;
+            if (wctCB != null) {
+                throw new IllegalArgumentException("Can't mix transitions that require finish"
+                        + " sync callback");
+            }
+            if (wct != null) {
+                if (mixed.mFinishWCT == null) {
+                    mixed.mFinishWCT = wct;
+                } else {
+                    mixed.mFinishWCT.merge(wct, true /* transfer */);
+                }
+            }
+            if (mixed.mInFlightSubAnimations > 0) return;
+            mActiveTransitions.remove(mixed);
+            mixed.mFinishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */);
+        };
+
+        // Dispatch the display change. This will most-likely be taken by the default handler.
+        // Do this first since the first handler used will apply the startT; the display change
+        // needs to take a screenshot before that happens so we need it to be the first handler.
+        mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, displayPart,
+                startT, finishT, finishCB, mSplitHandler);
+
+        // Note: at this point, startT has probably already been applied, so we are basically
+        // giving splitHandler an empty startT. This is currently OK because display-change will
+        // grab a screenshot and paste it on top anyways.
+        mSplitHandler.startPendingAnimation(
+                transition, everythingElse, startT, finishT, finishCB);
+        return true;
+    }
+
     @Override
     public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -266,6 +372,8 @@
                 } else {
                     mPipHandler.end();
                 }
+            } else if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) {
+                // queue
             } else {
                 throw new IllegalStateException("Playing a mixed transition with unknown type? "
                         + mixed.mType);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index cff60f5..1ae779e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -96,6 +96,7 @@
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.Transformation;
+import android.window.ScreenCapture;
 import android.window.TransitionInfo;
 import android.window.TransitionMetrics;
 import android.window.TransitionRequestInfo;
@@ -554,6 +555,12 @@
     private void edgeExtendWindow(TransitionInfo.Change change,
             Animation a, SurfaceControl.Transaction startTransaction,
             SurfaceControl.Transaction finishTransaction) {
+        // Do not create edge extension surface for transfer starting window change.
+        // The app surface could be empty thus nothing can draw on the hardware renderer, which will
+        // block this thread when calling Surface#unlockCanvasAndPost.
+        if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+            return;
+        }
         final Transformation transformationAtStart = new Transformation();
         a.getTransformationAt(0, transformationAtStart);
         final Transformation transformationAtEnd = new Transformation();
@@ -624,16 +631,16 @@
                 .setBufferSize(extensionRect.width(), extensionRect.height())
                 .build();
 
-        SurfaceControl.LayerCaptureArgs captureArgs =
-                new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend)
+        ScreenCapture.LayerCaptureArgs captureArgs =
+                new ScreenCapture.LayerCaptureArgs.Builder(surfaceToExtend)
                         .setSourceCrop(edgeBounds)
                         .setFrameScale(1)
                         .setPixelFormat(PixelFormat.RGBA_8888)
                         .setChildrenOnly(true)
                         .setAllowProtected(true)
                         .build();
-        final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer =
-                SurfaceControl.captureLayers(captureArgs);
+        final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
+                ScreenCapture.captureLayers(captureArgs);
 
         if (edgeBuffer == null) {
             ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index b647f43..2b27bae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -46,6 +46,7 @@
 import android.view.SurfaceSession;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+import android.window.ScreenCapture;
 import android.window.TransitionInfo;
 
 import com.android.internal.R;
@@ -144,14 +145,14 @@
                 t.reparent(mScreenshotLayer, mAnimLeash);
                 mStartLuma = change.getSnapshotLuma();
             } else {
-                SurfaceControl.LayerCaptureArgs args =
-                        new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+                ScreenCapture.LayerCaptureArgs args =
+                        new ScreenCapture.LayerCaptureArgs.Builder(mSurfaceControl)
                                 .setCaptureSecureLayers(true)
                                 .setAllowProtected(true)
                                 .setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
                                 .build();
-                SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                        SurfaceControl.captureLayers(args);
+                ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                        ScreenCapture.captureLayers(args);
                 if (screenshotBuffer == null) {
                     Slog.w(TAG, "Unable to take screenshot of display");
                     return;
@@ -481,8 +482,8 @@
         }
 
         Rect crop = new Rect(0, 0, bounds.width(), bounds.height());
-        SurfaceControl.ScreenshotHardwareBuffer buffer =
-                SurfaceControl.captureLayers(surfaceControl, crop, 1);
+        ScreenCapture.ScreenshotHardwareBuffer buffer =
+                ScreenCapture.captureLayers(surfaceControl, crop, 1);
         if (buffer == null) {
             return 0;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
deleted file mode 100644
index 678e91f..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.transition;
-
-import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.sysui.ShellInit;
-
-import java.util.Optional;
-
-/**
- * Handles transitions between the Splitscreen and PIP components.
- */
-public class SplitscreenPipMixedHandler {
-
-    private final Optional<SplitScreenController> mSplitScreenOptional;
-    private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
-    private final Transitions mTransitions;
-
-    public SplitscreenPipMixedHandler(ShellInit shellInit,
-            Optional<SplitScreenController> splitScreenControllerOptional,
-            Optional<PipTouchHandler> pipTouchHandlerOptional,
-            Transitions transitions) {
-        mSplitScreenOptional = splitScreenControllerOptional;
-        mPipTouchHandlerOptional = pipTouchHandlerOptional;
-        mTransitions = transitions;
-        if (Transitions.ENABLE_SHELL_TRANSITIONS
-                && mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
-            shellInit.addInitCallback(this::onInit, this);
-        }
-    }
-
-    private void onInit() {
-        // Special handling for initializing based on multiple components
-        final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
-                mPipTouchHandlerOptional.get().getTransitionHandler(),
-                mSplitScreenOptional.get().getTransitionHandler());
-        // Added at end so that it has highest priority.
-        mTransitions.addHandler(mixedHandler);
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
index 2cff171..c045ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.util;
 
+import android.annotation.IntDef;
 import android.app.ActivityManager;
 import android.app.WindowConfiguration;
 import android.os.Parcel;
@@ -24,40 +25,143 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Simple container for recent tasks.  May contain either a single or pair of tasks.
  */
 public class GroupedRecentTaskInfo implements Parcelable {
-    public @NonNull ActivityManager.RecentTaskInfo mTaskInfo1;
-    public @Nullable ActivityManager.RecentTaskInfo mTaskInfo2;
-    public @Nullable SplitBounds mSplitBounds;
 
-    public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1) {
-        this(task1, null, null);
+    public static final int TYPE_SINGLE = 1;
+    public static final int TYPE_SPLIT = 2;
+    public static final int TYPE_FREEFORM = 3;
+
+    @IntDef(prefix = {"TYPE_"}, value = {
+            TYPE_SINGLE,
+            TYPE_SPLIT,
+            TYPE_FREEFORM
+    })
+    public @interface GroupType {}
+
+    @NonNull
+    private final ActivityManager.RecentTaskInfo[] mTasks;
+    @Nullable
+    private final SplitBounds mSplitBounds;
+    @GroupType
+    private final int mType;
+
+    /**
+     * Create new for a single task
+     */
+    public static GroupedRecentTaskInfo forSingleTask(
+            @NonNull ActivityManager.RecentTaskInfo task) {
+        return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null,
+                TYPE_SINGLE);
     }
 
-    public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1,
-            @Nullable ActivityManager.RecentTaskInfo task2,
-            @Nullable SplitBounds splitBounds) {
-        mTaskInfo1 = task1;
-        mTaskInfo2 = task2;
+    /**
+     * Create new for a pair of tasks in split screen
+     */
+    public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1,
+            @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) {
+        return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2},
+                splitBounds, TYPE_SPLIT);
+    }
+
+    /**
+     * Create new for a group of freeform tasks
+     */
+    public static GroupedRecentTaskInfo forFreeformTasks(
+            @NonNull ActivityManager.RecentTaskInfo... tasks) {
+        return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM);
+    }
+
+    private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks,
+            @Nullable SplitBounds splitBounds, @GroupType int type) {
+        mTasks = tasks;
         mSplitBounds = splitBounds;
+        mType = type;
     }
 
     GroupedRecentTaskInfo(Parcel parcel) {
-        mTaskInfo1 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
-        mTaskInfo2 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
+        mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR);
         mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR);
+        mType = parcel.readInt();
+    }
+
+    /**
+     * Get primary {@link ActivityManager.RecentTaskInfo}
+     */
+    @NonNull
+    public ActivityManager.RecentTaskInfo getTaskInfo1() {
+        return mTasks[0];
+    }
+
+    /**
+     * Get secondary {@link ActivityManager.RecentTaskInfo}.
+     *
+     * Used in split screen.
+     */
+    @Nullable
+    public ActivityManager.RecentTaskInfo getTaskInfo2() {
+        if (mTasks.length > 1) {
+            return mTasks[1];
+        }
+        return null;
+    }
+
+    /**
+     * Get all {@link ActivityManager.RecentTaskInfo}s grouped together.
+     */
+    @NonNull
+    public List<ActivityManager.RecentTaskInfo> getTaskInfoList() {
+        return Arrays.asList(mTasks);
+    }
+
+    /**
+     * Return {@link SplitBounds} if this is a split screen entry or {@code null}
+     */
+    @Nullable
+    public SplitBounds getSplitBounds() {
+        return mSplitBounds;
+    }
+
+    /**
+     * Get type of this recents entry. One of {@link GroupType}
+     */
+    @GroupType
+    public int getType() {
+        return mType;
     }
 
     @Override
     public String toString() {
-        String taskString = "Task1: " + getTaskInfo(mTaskInfo1)
-                + ", Task2: " + getTaskInfo(mTaskInfo2);
-        if (mSplitBounds != null) {
-            taskString += ", SplitBounds: " + mSplitBounds.toString();
+        StringBuilder taskString = new StringBuilder();
+        for (int i = 0; i < mTasks.length; i++) {
+            if (i == 0) {
+                taskString.append("Task");
+            } else {
+                taskString.append(", Task");
+            }
+            taskString.append(i + 1).append(": ").append(getTaskInfo(mTasks[i]));
         }
-        return taskString;
+        if (mSplitBounds != null) {
+            taskString.append(", SplitBounds: ").append(mSplitBounds);
+        }
+        taskString.append(", Type=");
+        switch (mType) {
+            case TYPE_SINGLE:
+                taskString.append("TYPE_SINGLE");
+                break;
+            case TYPE_SPLIT:
+                taskString.append("TYPE_SPLIT");
+                break;
+            case TYPE_FREEFORM:
+                taskString.append("TYPE_FREEFORM");
+                break;
+        }
+        return taskString.toString();
     }
 
     private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
@@ -74,9 +178,9 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeTypedObject(mTaskInfo1, flags);
-        parcel.writeTypedObject(mTaskInfo2, flags);
+        parcel.writeTypedArray(mTasks, flags);
         parcel.writeTypedObject(mSplitBounds, flags);
+        parcel.writeInt(mType);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index a8154e8..2b162ae 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -68,9 +68,7 @@
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
             setup {
-                test {
-                    testSpec.setIsTablet(wmHelper.currentState.wmState.isTablet)
-                }
+                testSpec.setIsTablet(wmHelper.currentState.wmState.isTablet)
             }
             transition()
         }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index cc987dc..5597990 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -20,6 +20,7 @@
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.traces.layers.LayerTraceEntrySubject
 import com.android.server.wm.flicker.traces.layers.LayersTraceSubject
 import com.android.server.wm.traces.common.IComponentMatcher
@@ -99,7 +100,7 @@
     portraitPosTop: Boolean
 ) {
     assertLayers {
-        this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
+        this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
             .then()
             .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
             .then()
@@ -108,6 +109,32 @@
     }
 }
 
+fun FlickerTestParameter.splitAppLayerBoundsBecomesVisibleByDrag(
+    component: IComponentMatcher
+) {
+    assertLayers {
+        if (isShellTransitionsEnabled) {
+            this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
+                .then()
+                .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
+                .then()
+                // TODO(b/245472831): Verify the component should snap to divider.
+                .isVisible(component)
+        } else {
+            this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
+                .then()
+                .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
+                .then()
+                // TODO(b/245472831): Verify the component should snap to divider.
+                .isVisible(component)
+                .then()
+                .isInvisible(component, isOptional = true)
+                .then()
+                .isVisible(component)
+        }
+    }
+}
+
 fun FlickerTestParameter.splitAppLayerBoundsBecomesInvisible(
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 298bf68..1390334 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -55,21 +55,17 @@
     ): FlickerBuilder.() -> Unit {
         return {
             setup {
-                test {
-                    notifyManager.setBubblesAllowed(testApp.`package`,
-                        uid, NotificationManager.BUBBLE_PREFERENCE_ALL)
-                    testApp.launchViaIntent(wmHelper)
-                    waitAndGetAddBubbleBtn()
-                    waitAndGetCancelAllBtn()
-                }
+                notifyManager.setBubblesAllowed(testApp.`package`,
+                    uid, NotificationManager.BUBBLE_PREFERENCE_ALL)
+                testApp.launchViaIntent(wmHelper)
+                waitAndGetAddBubbleBtn()
+                waitAndGetCancelAllBtn()
             }
 
             teardown {
-                test {
-                    notifyManager.setBubblesAllowed(testApp.`package`,
-                        uid, NotificationManager.BUBBLE_PREFERENCE_NONE)
-                    testApp.exit()
-                }
+                notifyManager.setBubblesAllowed(testApp.`package`,
+                    uid, NotificationManager.BUBBLE_PREFERENCE_NONE)
+                testApp.exit()
             }
 
             extraSpec(this)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
index c44e250..ac4de47 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -54,10 +54,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
             setup {
-                eachRun {
-                    val addBubbleBtn = waitAndGetAddBubbleBtn()
-                    addBubbleBtn?.click() ?: error("Add Bubble not found")
-                }
+                val addBubbleBtn = waitAndGetAddBubbleBtn()
+                addBubbleBtn?.click() ?: error("Add Bubble not found")
             }
             transitions {
                 wm.run { wm.defaultDisplay.getMetrics(displaySize) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
index bab0112..7807854 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
@@ -48,10 +48,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
             setup {
-                test {
-                    val addBubbleBtn = waitAndGetAddBubbleBtn()
-                    addBubbleBtn?.click() ?: error("Add Bubble not found")
-                }
+                val addBubbleBtn = waitAndGetAddBubbleBtn()
+                addBubbleBtn?.click() ?: error("Add Bubble not found")
             }
             transitions {
                 val showBubble = device.wait(
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
index 47557bc..49681e1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
@@ -49,15 +49,13 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
             setup {
-                eachRun {
-                    val addBubbleBtn = waitAndGetAddBubbleBtn()
-                    addBubbleBtn?.click() ?: error("Bubble widget not found")
-                    device.sleep()
-                    wmHelper.StateSyncBuilder()
-                        .withoutTopVisibleAppWindows()
-                        .waitForAndVerify()
-                    device.wakeUp()
-                }
+                val addBubbleBtn = waitAndGetAddBubbleBtn()
+                addBubbleBtn?.click() ?: error("Bubble widget not found")
+                device.sleep()
+                wmHelper.StateSyncBuilder()
+                    .withoutTopVisibleAppWindows()
+                    .waitForAndVerify()
+                device.wakeUp()
             }
             transitions {
                 // Swipe & wait for the notification shade to expand so all can be seen
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
index 3ad92f8..fac0f73 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.os.SystemClock
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
@@ -57,20 +56,18 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
             setup {
-                test {
-                    for (i in 1..3) {
-                        val addBubbleBtn = waitAndGetAddBubbleBtn() ?: error("Add Bubble not found")
-                        addBubbleBtn.click()
-                        SystemClock.sleep(1000)
-                    }
-                    val showBubble = device.wait(
-                        Until.findObject(
-                            By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)
-                        ), FIND_OBJECT_TIMEOUT
-                    ) ?: error("Show bubble not found")
-                    showBubble.click()
+                for (i in 1..3) {
+                    val addBubbleBtn = waitAndGetAddBubbleBtn() ?: error("Add Bubble not found")
+                    addBubbleBtn.click()
                     SystemClock.sleep(1000)
                 }
+                val showBubble = device.wait(
+                    Until.findObject(
+                        By.res(SYSTEM_UI_PACKAGE, BUBBLE_RES_NAME)
+                    ), FIND_OBJECT_TIMEOUT
+                ) ?: error("Show bubble not found")
+                showBubble.click()
+                SystemClock.sleep(1000)
             }
             transitions {
                 val bubbles: List<UiObject2> = device.wait(
@@ -92,70 +89,4 @@
             this.isVisible(testApp)
         }
     }
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 87fa548..9684bb3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -17,12 +17,17 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -59,25 +64,26 @@
      */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
-            setupAndTeardown(this)
             setup {
-                eachRun {
-                    pipApp.launchViaIntent(wmHelper)
-                    pipApp.enableAutoEnterForPipActivity()
-                }
+                removeAllTasksButHome()
+                device.wakeUpAndGoToHomeScreen()
+                pipApp.launchViaIntent(wmHelper)
+                pipApp.enableAutoEnterForPipActivity()
             }
             teardown {
-                eachRun {
-                    // close gracefully so that onActivityUnpinned() can be called before force exit
-                    pipApp.closePipWindow(wmHelper)
-                    pipApp.exit(wmHelper)
-                }
+                // close gracefully so that onActivityUnpinned() can be called before force exit
+                pipApp.closePipWindow(wmHelper)
+
+                setRotation(Surface.ROTATION_0)
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                pipApp.exit(wmHelper)
             }
             transitions {
                 tapl.goHome()
             }
         }
 
+    @FlakyTest
     @Test
     override fun pipLayerReduces() {
         testSpec.assertLayers {
@@ -91,6 +97,7 @@
     /**
      * Checks that [pipApp] window is animated towards default position in right bottom corner
      */
+    @Presubmit
     @Test
     fun pipLayerMovesTowardsRightBottomCorner() {
         // in gestural nav the swipe makes PiP first go upwards
@@ -106,66 +113,11 @@
         }
     }
 
+    @Presubmit
     @Test
     override fun focusChanges() {
         // in gestural nav the focus goes to different activity on swipe up
         Assume.assumeFalse(testSpec.isGesturalNavigation)
         super.focusChanges()
     }
-
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun pipAppLayerAlwaysVisible() = super.pipAppLayerAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun pipLayerRemainInsideVisibleBounds() = super.pipLayerRemainInsideVisibleBounds()
-
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
-    @Postsubmit
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 42aac57..59f7ecf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,14 +17,17 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
+import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -60,24 +63,24 @@
      */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
-            setupAndTeardown(this)
             setup {
-                eachRun {
-                    pipApp.launchViaIntent(wmHelper)
-                    pipApp.enableEnterPipOnUserLeaveHint()
-                }
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                device.wakeUpAndGoToHomeScreen()
+                device.wakeUpAndGoToHomeScreen()
+                pipApp.launchViaIntent(wmHelper)
+                pipApp.enableEnterPipOnUserLeaveHint()
             }
             teardown {
-                eachRun {
-                    pipApp.exit(wmHelper)
-                }
+                setRotation(Surface.ROTATION_0)
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                pipApp.exit(wmHelper)
             }
             transitions {
                 tapl.goHome()
             }
         }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
         if (!testSpec.isGesturalNavigation) super.pipAppLayerAlwaysVisible() else {
@@ -90,7 +93,7 @@
         }
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun pipLayerReduces() {
         // in gestural nav the pip enters through alpha animation
@@ -98,7 +101,7 @@
         super.pipLayerReduces()
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun focusChanges() {
         // in gestural nav the focus goes to different activity on swipe up
@@ -106,11 +109,6 @@
         super.focusChanges()
     }
 
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun pipAppWindowAlwaysVisible() = super.pipAppWindowAlwaysVisible()
-
     @Presubmit
     @Test
     override fun entireScreenCovered() {
@@ -125,7 +123,7 @@
         super.entireScreenCovered()
     }
 
-    @Postsubmit
+    @Presubmit
     @Test
     override fun pipLayerRemainInsideVisibleBounds() {
         if (!testSpec.isGesturalNavigation) super.pipLayerRemainInsideVisibleBounds() else {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index b1b9736..c9e38e4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -25,6 +25,9 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group3
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -59,16 +62,15 @@
     /** {@inheritDoc}  */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
-            setupAndTeardown(this)
             setup {
-                eachRun {
-                    pipApp.launchViaIntent(wmHelper)
-                }
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                device.wakeUpAndGoToHomeScreen()
+                pipApp.launchViaIntent(wmHelper)
             }
             teardown {
-                eachRun {
-                    pipApp.exit(wmHelper)
-                }
+                setRotation(Surface.ROTATION_0)
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                pipApp.exit(wmHelper)
             }
             transitions {
                 pipApp.clickEnterPipButton(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 3bd2bf3..87d800c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -29,7 +29,10 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
+import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -78,29 +81,28 @@
      */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
-            setupAndTeardown(this)
-
             setup {
-                eachRun {
-                    // Launch a portrait only app on the fullscreen stack
-                    testApp.launchViaIntent(
-                        wmHelper, stringExtras = mapOf(
-                            EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString()
-                        )
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                device.wakeUpAndGoToHomeScreen()
+
+                // Launch a portrait only app on the fullscreen stack
+                testApp.launchViaIntent(
+                    wmHelper, stringExtras = mapOf(
+                        EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString()
                     )
-                    // Launch the PiP activity fixed as landscape
-                    pipApp.launchViaIntent(
-                        wmHelper, stringExtras = mapOf(
-                            EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()
-                        )
+                )
+                // Launch the PiP activity fixed as landscape
+                pipApp.launchViaIntent(
+                    wmHelper, stringExtras = mapOf(
+                        EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()
                     )
-                }
+                )
             }
             teardown {
-                eachRun {
-                    pipApp.exit(wmHelper)
-                    testApp.exit(wmHelper)
-                }
+                setRotation(Surface.ROTATION_0)
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                pipApp.exit(wmHelper)
+                testApp.exit(wmHelper)
             }
             transitions {
                 // Enter PiP, and assert that the PiP is within bounds now that the device is back
@@ -229,11 +231,6 @@
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 227313015)
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index fd1fe65..0f7d8a9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -33,14 +32,10 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = true) {
             setup {
-                eachRun {
-                    this.setRotation(testSpec.startRotation)
-                }
+                this.setRotation(testSpec.startRotation)
             }
             teardown {
-                eachRun {
-                    this.setRotation(Surface.ROTATION_0)
-                }
+                this.setRotation(Surface.ROTATION_0)
             }
         }
 
@@ -94,63 +89,4 @@
                 .isVisible(LAUNCHER)
         }
     }
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 39a7017..53450de 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -64,10 +64,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = true) {
             setup {
-                eachRun {
-                    // launch an app behind the pip one
-                    testApp.launchViaIntent(wmHelper)
-                }
+                // launch an app behind the pip one
+                testApp.launchViaIntent(wmHelper)
             }
             transitions {
                 // This will bring PipApp to fullscreen
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index 421a6fc..75018d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -64,10 +64,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = true) {
             setup {
-                eachRun {
-                    // launch an app behind the pip one
-                    testApp.launchViaIntent(wmHelper)
-                }
+                // launch an app behind the pip one
+                testApp.launchViaIntent(wmHelper)
             }
             transitions {
                 // This will bring PipApp to fullscreen
@@ -80,7 +78,12 @@
         }
 
     /** {@inheritDoc}  */
-    @FlakyTest(bugId = 206753786)
+    @FlakyTest
+    @Test
+    override fun entireScreenCovered() = super.entireScreenCovered()
+
+    /** {@inheritDoc}  */
+    @Presubmit
     @Test
     override fun statusBarLayerPositionAtStartAndEnd() {
         Assume.assumeFalse(isShellTransitionsEnabled)
@@ -109,11 +112,6 @@
         super.pipLayerExpands()
     }
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 227313015)
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 825aca3..4d39ec5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -111,7 +111,7 @@
     /**
      * Checks that the visible region of [pipApp] always expands during the animation
      */
-    @FlakyTest(bugId = 228012337)
+    @Presubmit
     @Test
     fun pipLayerExpands() {
         testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index d3e2ce15..de8c0093 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -62,12 +62,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = false) {
             teardown {
-                eachRun {
-                    testApp.launchViaIntent(wmHelper)
-                }
-                test {
-                    testApp.exit(wmHelper)
-                }
+                testApp.launchViaIntent(wmHelper)
+                testApp.exit(wmHelper)
             }
             transitions {
                 tapl.pressHome()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index 3d64bbe..3e08bfb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.RequiresDevice
 import android.view.Surface
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -29,7 +28,6 @@
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -72,12 +70,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = false) {
             teardown {
-                eachRun {
-                    tapl.pressHome()
-                }
-                test {
-                    testApp.exit(wmHelper)
-                }
+                tapl.pressHome()
+                testApp.exit(wmHelper)
             }
             transitions {
                 testApp.launchViaIntent(wmHelper)
@@ -88,12 +82,6 @@
         current.isLowerOrEqual(previous.region)
     }
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 206753786)
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index be39fae..27fc2ed 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
@@ -59,16 +58,12 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = false) {
             setup {
-                test {
-                    imeApp.launchViaIntent(wmHelper)
-                    setRotation(testSpec.startRotation)
-                }
+                imeApp.launchViaIntent(wmHelper)
+                setRotation(testSpec.startRotation)
             }
             teardown {
-                test {
-                    imeApp.exit(wmHelper)
-                    setRotation(Surface.ROTATION_0)
-                }
+                imeApp.exit(wmHelper)
+                setRotation(Surface.ROTATION_0)
             }
             transitions {
                 // open the soft keyboard
@@ -80,12 +75,6 @@
             }
         }
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 206753786)
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
     /**
      * Ensure the pip window remains visible throughout any keyboard interactions
      */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 4dc9858..fd5ff29 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.Presubmit
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,7 +25,6 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group4
 import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
@@ -74,12 +74,8 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition(eachRun = false) {
             setup {
-                test {
-                    fixedApp.launchViaIntent(wmHelper)
-                }
-                eachRun {
-                    setRotation(testSpec.startRotation)
-                }
+                fixedApp.launchViaIntent(wmHelper)
+                setRotation(testSpec.startRotation)
             }
             transitions {
                 setRotation(testSpec.endRotation)
@@ -87,13 +83,6 @@
         }
 
     /**
-     * Checks that all parts of the screen are covered at the start and end of the transition
-     */
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun entireScreenCovered() = testSpec.entireScreenCovered()
-
-    /**
      * Checks the position of the navigation bar at the start and end of the transition
      */
     @FlakyTest(bugId = 240499181)
@@ -103,7 +92,7 @@
     /**
      * Checks that [fixedApp] layer is within [screenBoundsStart] at the start of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun fixedAppLayer_StartingBounds() {
         testSpec.assertLayersStart {
@@ -114,7 +103,7 @@
     /**
      * Checks that [fixedApp] layer is within [screenBoundsEnd] at the end of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun fixedAppLayer_EndingBounds() {
         testSpec.assertLayersEnd {
@@ -126,7 +115,7 @@
      * Checks that [fixedApp] plus [pipApp] layers are within [screenBoundsEnd] at the start
      * of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun appLayers_StartingBounds() {
         testSpec.assertLayersStart {
@@ -138,7 +127,7 @@
      * Checks that [fixedApp] plus [pipApp] layers are within [screenBoundsEnd] at the end
      * of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun appLayers_EndingBounds() {
         testSpec.assertLayersEnd {
@@ -158,7 +147,7 @@
     /**
      * Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipLayerRotates_StartingBounds() {
         pipLayerRotates_StartingBounds_internal()
@@ -167,7 +156,7 @@
     /**
      * Checks that [pipApp] layer is within [screenBoundsEnd] at the end of the transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipLayerRotates_EndingBounds() {
         testSpec.assertLayersEnd {
@@ -179,7 +168,7 @@
      * Ensure that the [pipApp] window does not obscure the [fixedApp] at the start of the
      * transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipIsAboveFixedAppWindow_Start() {
         testSpec.assertWmStart {
@@ -191,7 +180,7 @@
      * Ensure that the [pipApp] window does not obscure the [fixedApp] at the end of the
      * transition
      */
-    @FlakyTest(bugId = 240499181)
+    @Presubmit
     @Test
     fun pipIsAboveFixedAppWindow_End() {
         testSpec.assertWmEnd {
@@ -205,54 +194,6 @@
         super.navBarLayerIsVisibleAtStartAndEnd()
     }
 
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun navBarWindowIsAlwaysVisible() {
-        super.navBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() {
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() {
-        super.statusBarLayerPositionAtStartAndEnd()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() {
-        super.statusBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() {
-        super.taskBarLayerIsVisibleAtStartAndEnd()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun taskBarWindowIsAlwaysVisible() {
-        super.taskBarWindowIsAlwaysVisible()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-    }
-
-    @FlakyTest(bugId = 240499181)
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-    }
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
index 0dd38cd..737f16a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
@@ -25,6 +25,7 @@
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
+import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -59,4 +60,10 @@
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
     }
+
+    /** {@inheritDoc}  */
+    @FlakyTest
+    @Test
+    override fun navBarLayerPositionAtStartAndEnd() =
+        super.navBarLayerPositionAtStartAndEnd()
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index 9ade597..faf6afc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -23,7 +23,6 @@
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import com.android.wm.shell.flicker.BaseTest
 import com.android.wm.shell.flicker.helpers.PipAppHelper
@@ -57,28 +56,6 @@
     }
 
     /**
-     * Gets a configuration that handles basic setup and teardown of pip tests
-     */
-    protected val setupAndTeardown: FlickerBuilder.() -> Unit
-        get() = {
-            setup {
-                test {
-                    removeAllTasksButHome()
-                    device.wakeUpAndGoToHomeScreen()
-                }
-            }
-            teardown {
-                eachRun {
-                    setRotation(Surface.ROTATION_0)
-                }
-                test {
-                    removeAllTasksButHome()
-                    pipApp.exit(wmHelper)
-                }
-            }
-        }
-
-    /**
      * Gets a configuration that handles basic setup and teardown of pip tests and that
      * launches the Pip app for test
      *
@@ -93,30 +70,27 @@
         extraSpec: FlickerBuilder.() -> Unit = {}
     ): FlickerBuilder.() -> Unit {
         return {
-            setupAndTeardown(this)
-
             setup {
-                test {
-                    if (!eachRun) {
-                        pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
-                    }
+                setRotation(Surface.ROTATION_0)
+                removeAllTasksButHome()
+
+                if (!eachRun) {
+                    pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
                 }
-                eachRun {
-                    if (eachRun) {
-                        pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
-                    }
+                if (eachRun) {
+                    pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
                 }
             }
             teardown {
-                eachRun {
-                    if (eachRun) {
-                        pipApp.exit(wmHelper)
-                    }
+                setRotation(Surface.ROTATION_0)
+                removeAllTasksButHome()
+                pipApp.exit(wmHelper)
+
+                if (eachRun) {
+                    pipApp.exit(wmHelper)
                 }
-                test {
-                    if (!eachRun) {
-                        pipApp.exit(wmHelper)
-                    }
+                if (!eachRun) {
+                    pipApp.exit(wmHelper)
                 }
             }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index d5de22f..866e4e8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -61,33 +61,26 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             setup {
-                test {
-                    removeAllTasksButHome()
-                    device.wakeUpAndGoToHomeScreen()
-                }
-                eachRun {
-                    // Launch the PiP activity fixed as landscape.
-                    pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
-                        EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
-                    // Enter PiP.
-                    broadcastActionTrigger.doAction(Components.PipActivity.ACTION_ENTER_PIP)
-                    // System bar may fade out during fixed rotation.
-                    wmHelper.StateSyncBuilder()
-                        .withPipShown()
-                        .withRotation(Surface.ROTATION_0)
-                        .withNavOrTaskBarVisible()
-                        .withStatusBarVisible()
-                        .waitForAndVerify()
-                }
+                removeAllTasksButHome()
+                device.wakeUpAndGoToHomeScreen()
+
+                // Launch the PiP activity fixed as landscape.
+                pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
+                    EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
+                // Enter PiP.
+                broadcastActionTrigger.doAction(Components.PipActivity.ACTION_ENTER_PIP)
+                // System bar may fade out during fixed rotation.
+                wmHelper.StateSyncBuilder()
+                    .withPipShown()
+                    .withRotation(Surface.ROTATION_0)
+                    .withNavOrTaskBarVisible()
+                    .withStatusBarVisible()
+                    .waitForAndVerify()
             }
             teardown {
-                eachRun {
-                    pipApp.exit(wmHelper)
-                    setRotation(Surface.ROTATION_0)
-                }
-                test {
-                    removeAllTasksButHome()
-                }
+                pipApp.exit(wmHelper)
+                setRotation(Surface.ROTATION_0)
+                removeAllTasksButHome()
             }
             transitions {
                 // Launch the activity back into fullscreen and ensure that it is now in landscape
@@ -178,18 +171,6 @@
     /** {@inheritDoc}  */
     @Postsubmit
     @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc}  */
@@ -200,25 +181,8 @@
     /** {@inheritDoc}  */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
     override fun entireScreenCovered() = super.entireScreenCovered()
 
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 102a78b..3c439fd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -53,9 +54,7 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, textEditApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, textEditApp)
             }
             transitions {
                 SplitScreenHelper.copyContentInSplit(
@@ -63,32 +62,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerKeepVisible() = testSpec.layerKeepVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun textEditAppLayerKeepVisible() = testSpec.layerKeepVisible(textEditApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsKeepVisible() = testSpec.splitAppLayerBoundsKeepVisible(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun textEditAppBoundsKeepVisible() = testSpec.splitAppLayerBoundsKeepVisible(
         textEditApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowKeepVisible() = testSpec.appWindowKeepVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun textEditAppWindowKeepVisible() = testSpec.appWindowKeepVisible(textEditApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index bf91292..60e5f78 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -39,6 +40,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
+
 /**
  * Test dismiss split screen by dragging the divider bar.
  *
@@ -55,9 +57,7 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
                 if (tapl.isTablet) {
@@ -73,23 +73,28 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerBecomesInvisible() = testSpec.splitScreenDividerBecomesInvisible()
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsFullscreenAtEnd() {
@@ -112,10 +117,12 @@
         }
     }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 20a7423..4e8773f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -54,9 +55,7 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
                 tapl.goHome()
@@ -66,32 +65,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerBecomesInvisible() = testSpec.splitScreenDividerBecomesInvisible()
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
         secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 8f7673b..fddd84c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
@@ -53,23 +54,24 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
                 SplitScreenHelper.dragDividerToResizeAndWait(device, wmHelper)
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerKeepVisible() = testSpec.layerKeepVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerVisibilityChanges() {
@@ -82,19 +84,23 @@
         }
     }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowKeepVisible() = testSpec.appWindowKeepVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowKeepVisible() = testSpec.appWindowKeepVisible(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsChanges() = testSpec.splitAppLayerBoundsChanges(
         primaryApp, landscapePosLeft = true, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsChanges() = testSpec.splitAppLayerBoundsChanges(
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 8e2769f..a7c6898 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -25,12 +26,14 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
+import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
 import org.junit.Assume
@@ -65,10 +68,8 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    tapl.goHome()
-                    primaryApp.launchViaIntent(wmHelper)
-                }
+                tapl.goHome()
+                primaryApp.launchViaIntent(wmHelper)
             }
             transitions {
                 tapl.launchedAppState.taskbar
@@ -79,32 +80,72 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.splitScreenDividerBecomesVisible()
+    }
 
+    // TODO(b/245472831): Back to splitScreenDividerBecomesVisible after shell transition ready.
+    @IwTest(focusArea = "sysui")
+    @Presubmit
+    @Test
+    fun splitScreenDividerIsVisibleAtEnd_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        testSpec.assertLayersEnd {
+            this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+        }
+    }
+
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.assertLayers {
+            this.isInvisible(secondaryApp)
+                .then()
+                .isVisible(secondaryApp)
+                .then()
+                .isInvisible(secondaryApp)
+                .then()
+                .isVisible(secondaryApp)
+        }
+    }
 
+    // TODO(b/245472831): Align to legacy transition after shell transition ready.
+    @Presubmit
+    @Test
+    fun secondaryAppLayerBecomesVisible_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        testSpec.layerBecomesVisible(secondaryApp)
+    }
+
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = false, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisible(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
+        secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index 531d376..7d8a8db 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -27,11 +28,13 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
+import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
 import org.junit.Assume
@@ -69,57 +72,92 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    // Send a notification
-                    sendNotificationApp.launchViaIntent(wmHelper)
-                    val sendNotification = device.wait(
-                        Until.findObject(By.text("Send Notification")),
-                        SplitScreenHelper.TIMEOUT_MS
-                    )
-                    sendNotification?.click() ?: error("Send notification button not found")
+                // Send a notification
+                sendNotificationApp.launchViaIntent(wmHelper)
+                val sendNotification = device.wait(
+                    Until.findObject(By.text("Send Notification")),
+                    SplitScreenHelper.TIMEOUT_MS
+                )
+                sendNotification?.click() ?: error("Send notification button not found")
 
-                    tapl.goHome()
-                    primaryApp.launchViaIntent(wmHelper)
-                }
+                tapl.goHome()
+                primaryApp.launchViaIntent(wmHelper)
             }
             transitions {
                 SplitScreenHelper.dragFromNotificationToSplit(instrumentation, device, wmHelper)
                 SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
             }
             teardown {
-                eachRun {
-                    sendNotificationApp.exit(wmHelper)
-                }
+                sendNotificationApp.exit(wmHelper)
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.splitScreenDividerBecomesVisible()
+    }
 
+    // TODO(b/245472831): Back to splitScreenDividerBecomesVisible after shell transition ready.
+    @IwTest(focusArea = "sysui")
+    @Presubmit
+    @Test
+    fun splitScreenDividerIsVisibleAtEnd_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        testSpec.assertLayersEnd {
+            this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+        }
+    }
+
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() =
-        testSpec.layerBecomesVisible(sendNotificationApp)
+    fun secondaryAppLayerBecomesVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.assertLayers {
+            this.isInvisible(sendNotificationApp)
+                .then()
+                .isVisible(sendNotificationApp)
+                .then()
+                .isInvisible(sendNotificationApp)
+                .then()
+                .isVisible(sendNotificationApp)
+        }
+    }
 
+    // TODO(b/245472831): Align to legacy transition after shell transition ready.
+    @Presubmit
+    @Test
+    fun secondaryAppLayerBecomesVisible_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        testSpec.layerBecomesVisible(sendNotificationApp)
+    }
+
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = false, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisible(
-        sendNotificationApp, landscapePosLeft = true, portraitPosTop = true)
+    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
+        sendNotificationApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(sendNotificationApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index ea43c7e..bfd8a3a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -25,12 +26,14 @@
 import com.android.server.wm.flicker.FlickerTestParameterFactory
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
-import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisible
+import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesVisibleByDrag
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
 import org.junit.Assume
@@ -66,13 +69,11 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    tapl.goHome()
-                    SplitScreenHelper.createShortcutOnHotseatIfNotExist(
-                        tapl, secondaryApp.appName
-                    )
-                    primaryApp.launchViaIntent(wmHelper)
-                }
+                tapl.goHome()
+                SplitScreenHelper.createShortcutOnHotseatIfNotExist(
+                    tapl, secondaryApp.appName
+                )
+                primaryApp.launchViaIntent(wmHelper)
             }
             transitions {
                 tapl.launchedAppState.taskbar
@@ -82,32 +83,72 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.splitScreenDividerBecomesVisible()
+    }
 
+    // TODO(b/245472831): Back to splitScreenDividerBecomesVisible after shell transition ready.
+    @IwTest(focusArea = "sysui")
+    @Presubmit
+    @Test
+    fun splitScreenDividerIsVisibleAtEnd_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        testSpec.assertLayersEnd {
+            this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+        }
+    }
+
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() {
+        Assume.assumeFalse(isShellTransitionsEnabled)
+        testSpec.assertLayers {
+            this.isInvisible(secondaryApp)
+                .then()
+                .isVisible(secondaryApp)
+                .then()
+                .isInvisible(secondaryApp)
+                .then()
+                .isVisible(secondaryApp)
+        }
+    }
 
+    // TODO(b/245472831): Align to legacy transition after shell transition ready.
+    @Presubmit
+    @Test
+    fun secondaryAppLayerBecomesVisible_ShellTransit() {
+        Assume.assumeTrue(isShellTransitionsEnabled)
+        testSpec.layerBecomesVisible(secondaryApp)
+    }
+
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = false, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisible(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
+        secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index 7ce23c5..cefb9f5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
@@ -53,16 +54,14 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    tapl.workspace.switchToOverview().dismissAllTasks()
-                    primaryApp.launchViaIntent(wmHelper)
-                    secondaryApp.launchViaIntent(wmHelper)
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withAppTransitionIdle()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                }
+                tapl.workspace.switchToOverview().dismissAllTasks()
+                primaryApp.launchViaIntent(wmHelper)
+                secondaryApp.launchViaIntent(wmHelper)
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withAppTransitionIdle()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
             }
             transitions {
                 SplitScreenHelper.splitFromOverview(tapl)
@@ -70,32 +69,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisible(
         secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index 81390b2..eab473c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -32,17 +32,13 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             setup {
-                test {
-                    tapl.setEnableRotation(true)
-                    setRotation(testSpec.startRotation)
-                    tapl.setExpectedRotation(testSpec.startRotation)
-                }
+                tapl.setEnableRotation(true)
+                setRotation(testSpec.startRotation)
+                tapl.setExpectedRotation(testSpec.startRotation)
             }
             teardown {
-                eachRun {
-                    primaryApp.exit(wmHelper)
-                    secondaryApp.exit(wmHelper)
-                }
+                primaryApp.exit(wmHelper)
+                secondaryApp.exit(wmHelper)
             }
         }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index 58f7b04..e174f5e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -53,9 +54,7 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
                 SplitScreenHelper.doubleTapDividerToSwitch(device)
@@ -65,32 +64,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         secondaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 0dd6706..20c6af7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -53,14 +54,12 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
 
-                    thirdApp.launchViaIntent(wmHelper)
-                    wmHelper.StateSyncBuilder()
-                        .withWindowSurfaceAppeared(thirdApp)
-                        .waitForAndVerify()
-                }
+                thirdApp.launchViaIntent(wmHelper)
+                wmHelper.StateSyncBuilder()
+                    .withWindowSurfaceAppeared(thirdApp)
+                    .waitForAndVerify()
             }
             transitions {
                 tapl.launchedAppState.quickSwitchToPreviousApp()
@@ -68,32 +67,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index dc8ba0c..cb9ca9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -52,14 +53,12 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
 
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                }
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
             }
             transitions {
                 tapl.workspace.quickSwitchToPreviousApp()
@@ -67,32 +66,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index e5924c5..2662767 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.splitscreen
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.WindowManagerPolicyConstants
@@ -52,14 +53,12 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
 
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                }
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
             }
             transitions {
                 tapl.workspace.switchToOverview()
@@ -69,32 +68,39 @@
             }
         }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
         secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index b2e45a6..a7234c1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -17,7 +17,7 @@
 package com.android.wm.shell.activityembedding;
 
 import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.window.TransitionInfo.FLAG_IS_EMBEDDED;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -57,7 +57,7 @@
     public void testStartAnimation() {
         final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
         final TransitionInfo.Change embeddingChange = createChange();
-        embeddingChange.setFlags(FLAG_IS_EMBEDDED);
+        embeddingChange.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
         info.addChange(embeddingChange);
         doReturn(mAnimator).when(mAnimRunner).createAnimator(any(), any(), any(), any());
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
index 84befdd..3792e83 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
@@ -16,6 +16,9 @@
 
 package com.android.wm.shell.activityembedding;
 
+import static android.window.TransitionInfo.FLAG_FILLS_TASK;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertNotNull;
@@ -24,6 +27,8 @@
 
 import android.animation.Animator;
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.graphics.Rect;
 import android.os.IBinder;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
@@ -80,4 +85,23 @@
         return new TransitionInfo.Change(mock(WindowContainerToken.class),
                 mock(SurfaceControl.class));
     }
+
+    /**
+     * Creates a mock {@link TransitionInfo.Change} with
+     * {@link TransitionInfo#FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY} flag.
+     */
+    static TransitionInfo.Change createEmbeddedChange(@NonNull Rect startBounds,
+            @NonNull Rect endBounds, @NonNull Rect taskBounds) {
+        final TransitionInfo.Change change = createChange();
+        change.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
+        change.setStartAbsBounds(startBounds);
+        change.setEndAbsBounds(endBounds);
+        if (taskBounds.width() == startBounds.width()
+                && taskBounds.height() == startBounds.height()
+                && taskBounds.width() == endBounds.width()
+                && taskBounds.height() == endBounds.height()) {
+            change.setFlags(FLAG_FILLS_TASK);
+        }
+        return change;
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
index cf43b00..baecf6f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
@@ -17,7 +17,6 @@
 package com.android.wm.shell.activityembedding;
 
 import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.window.TransitionInfo.FLAG_IS_EMBEDDED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 
@@ -29,6 +28,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.graphics.Rect;
 import android.window.TransitionInfo;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -48,6 +48,10 @@
 @RunWith(AndroidJUnit4.class)
 public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimationTestBase {
 
+    private static final Rect TASK_BOUNDS = new Rect(0, 0, 1000, 500);
+    private static final Rect EMBEDDED_LEFT_BOUNDS = new Rect(0, 0, 500, 500);
+    private static final Rect EMBEDDED_RIGHT_BOUNDS = new Rect(500, 0, 1000, 500);
+
     @Before
     public void setup() {
         super.setUp();
@@ -77,13 +81,13 @@
     @Test
     public void testStartAnimation_containsNonActivityEmbeddingChange() {
         final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
-        final TransitionInfo.Change embeddingChange = createChange();
-        embeddingChange.setFlags(FLAG_IS_EMBEDDED);
+        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_LEFT_BOUNDS,
+                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
         final TransitionInfo.Change nonEmbeddingChange = createChange();
         info.addChange(embeddingChange);
         info.addChange(nonEmbeddingChange);
 
-        // No-op
+        // No-op because it contains non-embedded change.
         assertFalse(mController.startAnimation(mTransition, info, mStartTransaction,
                 mFinishTransaction, mFinishCallback));
         verify(mAnimRunner, never()).startAnimation(any(), any(), any(), any());
@@ -93,13 +97,65 @@
     }
 
     @Test
-    public void testStartAnimation_onlyActivityEmbeddingChange() {
+    public void testStartAnimation_containsOnlyFillTaskActivityEmbeddingChange() {
         final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
-        final TransitionInfo.Change embeddingChange = createChange();
-        embeddingChange.setFlags(FLAG_IS_EMBEDDED);
+        final TransitionInfo.Change embeddingChange = createEmbeddedChange(TASK_BOUNDS, TASK_BOUNDS,
+                TASK_BOUNDS);
         info.addChange(embeddingChange);
 
-        // No-op
+        // No-op because it only contains embedded change that fills the Task. We will let the
+        // default handler to animate such transition.
+        assertFalse(mController.startAnimation(mTransition, info, mStartTransaction,
+                mFinishTransaction, mFinishCallback));
+        verify(mAnimRunner, never()).startAnimation(any(), any(), any(), any());
+        verifyNoMoreInteractions(mStartTransaction);
+        verifyNoMoreInteractions(mFinishTransaction);
+        verifyNoMoreInteractions(mFinishCallback);
+    }
+
+    @Test
+    public void testStartAnimation_containsActivityEmbeddingSplitChange() {
+        // Change that occupies only part of the Task.
+        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
+        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_LEFT_BOUNDS,
+                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
+        info.addChange(embeddingChange);
+
+        // ActivityEmbeddingController will handle such transition.
+        assertTrue(mController.startAnimation(mTransition, info, mStartTransaction,
+                mFinishTransaction, mFinishCallback));
+        verify(mAnimRunner).startAnimation(mTransition, info, mStartTransaction,
+                mFinishTransaction);
+        verify(mStartTransaction).apply();
+        verifyNoMoreInteractions(mFinishTransaction);
+    }
+
+    @Test
+    public void testStartAnimation_containsChangeEnterActivityEmbeddingSplit() {
+        // Change that is entering ActivityEmbedding split.
+        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
+        final TransitionInfo.Change embeddingChange = createEmbeddedChange(TASK_BOUNDS,
+                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
+        info.addChange(embeddingChange);
+
+        // ActivityEmbeddingController will handle such transition.
+        assertTrue(mController.startAnimation(mTransition, info, mStartTransaction,
+                mFinishTransaction, mFinishCallback));
+        verify(mAnimRunner).startAnimation(mTransition, info, mStartTransaction,
+                mFinishTransaction);
+        verify(mStartTransaction).apply();
+        verifyNoMoreInteractions(mFinishTransaction);
+    }
+
+    @Test
+    public void testStartAnimation_containsChangeExitActivityEmbeddingSplit() {
+        // Change that is exiting ActivityEmbedding split.
+        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
+        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_RIGHT_BOUNDS,
+                TASK_BOUNDS, TASK_BOUNDS);
+        info.addChange(embeddingChange);
+
+        // ActivityEmbeddingController will handle such transition.
         assertTrue(mController.startAnimation(mTransition, info, mStartTransaction,
                 mFinishTransaction, mFinishCallback));
         verify(mAnimRunner).startAnimation(mTransition, info, mStartTransaction,
@@ -115,8 +171,8 @@
                 () -> mController.onAnimationFinished(mTransition));
 
         final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
-        final TransitionInfo.Change embeddingChange = createChange();
-        embeddingChange.setFlags(FLAG_IS_EMBEDDED);
+        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_LEFT_BOUNDS,
+                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
         info.addChange(embeddingChange);
         mController.startAnimation(mTransition, info, mStartTransaction,
                 mFinishTransaction, mFinishCallback);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 1b5091f..a8d3bdc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -43,6 +43,7 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -99,7 +100,8 @@
     @Mock private TaskStackListenerImpl mMockTaskStackListener;
     @Mock private ShellExecutor mMockExecutor;
     @Mock private Optional<OneHandedController> mMockOneHandedController;
-    @Mock private PipParamsChangedForwarder mPipParamsChangedForwarder;
+    @Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder;
+    @Mock private DisplayInsetsController mMockDisplayInsetsController;
 
     @Mock private DisplayLayout mMockDisplayLayout1;
     @Mock private DisplayLayout mMockDisplayLayout2;
@@ -120,8 +122,8 @@
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mPipParamsChangedForwarder,
-                mMockOneHandedController, mMockExecutor);
+                mMockTaskStackListener, mMockPipParamsChangedForwarder,
+                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor);
         mShellInit.init();
         when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
         when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
@@ -186,8 +188,8 @@
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mPipParamsChangedForwarder,
-                mMockOneHandedController, mMockExecutor));
+                mMockTaskStackListener, mMockPipParamsChangedForwarder,
+                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
new file mode 100644
index 0000000..8ce3ca4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipDoubleTapHelperTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip.phone;
+
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_CUSTOM;
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_DEFAULT;
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.SIZE_SPEC_MAX;
+import static com.android.wm.shell.pip.phone.PipDoubleTapHelper.nextSizeSpec;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.pip.PipBoundsState;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+/**
+ * Unit test against {@link PipDoubleTapHelper}.
+ */
+@RunWith(AndroidTestingRunner.class)
+public class PipDoubleTapHelperTest extends ShellTestCase {
+    // represents the current pip window state and has information on current
+    // max, min, and normal sizes
+    @Mock private PipBoundsState mBoundStateMock;
+    // tied to boundsStateMock.getBounds() in setUp()
+    @Mock private Rect mBoundsMock;
+
+    // represents the most recent manually resized bounds
+    // i.e. dimensions from the most recent pinch in/out
+    @Mock private Rect mUserResizeBoundsMock;
+
+    // actual dimensions of the pip screen bounds
+    private static final int MAX_WIDTH = 100;
+    private static final int DEFAULT_WIDTH = 40;
+    private static final int MIN_WIDTH = 10;
+
+    private static final int AVERAGE_WIDTH = (MAX_WIDTH + MIN_WIDTH) / 2;
+
+    /**
+     * Initializes mocks and assigns values for different pip screen bounds.
+     */
+    @Before
+    public void setUp() {
+        // define pip bounds
+        when(mBoundStateMock.getMaxSize()).thenReturn(new Point(MAX_WIDTH, 20));
+        when(mBoundStateMock.getMinSize()).thenReturn(new Point(MIN_WIDTH, 2));
+
+        Rect rectMock = mock(Rect.class);
+        when(rectMock.width()).thenReturn(DEFAULT_WIDTH);
+        when(mBoundStateMock.getNormalBounds()).thenReturn(rectMock);
+
+        when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+        when(mBoundStateMock.getBounds()).thenReturn(mBoundsMock);
+    }
+
+    /**
+     * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+     *
+     * <p>when the user resizes the screen to a larger than the average but not the maximum width,
+     * then we toggle between {@code PipSizeSpec.CUSTOM} and {@code PipSizeSpec.DEFAULT}
+     */
+    @Test
+    public void testNextScreenSize_resizedWiderThanAverage_returnDefaultThenCustom() {
+        // make the user resize width in between MAX and average
+        when(mUserResizeBoundsMock.width()).thenReturn((MAX_WIDTH + AVERAGE_WIDTH) / 2);
+        // make current bounds same as resized bound since no double tap yet
+        when(mBoundsMock.width()).thenReturn((MAX_WIDTH + AVERAGE_WIDTH) / 2);
+
+        // then nextScreenSize() i.e. double tapping should
+        // toggle to DEFAULT state
+        Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+                SIZE_SPEC_DEFAULT);
+
+        // once we toggle to DEFAULT our screen size gets updated
+        // but not the user resize bounds
+        when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+
+        // then nextScreenSize() i.e. double tapping should
+        // toggle to CUSTOM state
+        Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+                SIZE_SPEC_CUSTOM);
+    }
+
+    /**
+     * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+     *
+     * <p>when the user resizes the screen to a smaller than the average but not the default width,
+     * then we toggle between {@code PipSizeSpec.CUSTOM} and {@code PipSizeSpec.MAX}
+     */
+    @Test
+    public void testNextScreenSize_resizedNarrowerThanAverage_returnMaxThenCustom() {
+        // make the user resize width in between MIN and average
+        when(mUserResizeBoundsMock.width()).thenReturn((MIN_WIDTH + AVERAGE_WIDTH) / 2);
+        // make current bounds same as resized bound since no double tap yet
+        when(mBoundsMock.width()).thenReturn((MIN_WIDTH + AVERAGE_WIDTH) / 2);
+
+        // then nextScreenSize() i.e. double tapping should
+        // toggle to MAX state
+        Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+                SIZE_SPEC_MAX);
+
+        // once we toggle to MAX our screen size gets updated
+        // but not the user resize bounds
+        when(mBoundsMock.width()).thenReturn(MAX_WIDTH);
+
+        // then nextScreenSize() i.e. double tapping should
+        // toggle to CUSTOM state
+        Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+                SIZE_SPEC_CUSTOM);
+    }
+
+    /**
+     * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+     *
+     * <p>when the user resizes the screen to exactly the maximum width
+     * then we toggle to {@code PipSizeSpec.DEFAULT}
+     */
+    @Test
+    public void testNextScreenSize_resizedToMax_returnDefault() {
+        // the resized width is the same as MAX_WIDTH
+        when(mUserResizeBoundsMock.width()).thenReturn(MAX_WIDTH);
+        // the current bounds are also at MAX_WIDTH
+        when(mBoundsMock.width()).thenReturn(MAX_WIDTH);
+
+        // then nextScreenSize() i.e. double tapping should
+        // toggle to DEFAULT state
+        Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+                SIZE_SPEC_DEFAULT);
+    }
+
+    /**
+     * Tests {@link PipDoubleTapHelper#nextSizeSpec(PipBoundsState, Rect)}.
+     *
+     * <p>when the user resizes the screen to exactly the default width
+     * then we toggle to {@code PipSizeSpec.MAX}
+     */
+    @Test
+    public void testNextScreenSize_resizedToDefault_returnMax() {
+        // the resized width is the same as DEFAULT_WIDTH
+        when(mUserResizeBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+        // the current bounds are also at DEFAULT_WIDTH
+        when(mBoundsMock.width()).thenReturn(DEFAULT_WIDTH);
+
+        // then nextScreenSize() i.e. double tapping should
+        // toggle to MAX state
+        Assert.assertSame(nextSizeSpec(mBoundStateMock, mUserResizeBoundsMock),
+                SIZE_SPEC_MAX);
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
new file mode 100644
index 0000000..baa06f2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.recents
+
+import android.app.ActivityManager
+import android.graphics.Rect
+import android.os.Parcel
+import android.testing.AndroidTestingRunner
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import com.android.wm.shell.util.GroupedRecentTaskInfo.CREATOR
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SINGLE
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT
+import com.android.wm.shell.util.SplitBounds
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+/**
+ * Tests for [GroupedRecentTaskInfo]
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class GroupedRecentTaskInfoTest : ShellTestCase() {
+
+    @Test
+    fun testSingleTask_hasCorrectType() {
+        assertThat(singleTaskGroupInfo().type).isEqualTo(TYPE_SINGLE)
+    }
+
+    @Test
+    fun testSingleTask_task1Set_task2Null() {
+        val group = singleTaskGroupInfo()
+        assertThat(group.taskInfo1.taskId).isEqualTo(1)
+        assertThat(group.taskInfo2).isNull()
+    }
+
+    @Test
+    fun testSingleTask_taskInfoList_hasOneTask() {
+        val list = singleTaskGroupInfo().taskInfoList
+        assertThat(list).hasSize(1)
+        assertThat(list[0].taskId).isEqualTo(1)
+    }
+
+    @Test
+    fun testSplitTasks_hasCorrectType() {
+        assertThat(splitTasksGroupInfo().type).isEqualTo(TYPE_SPLIT)
+    }
+
+    @Test
+    fun testSplitTasks_task1Set_task2Set_boundsSet() {
+        val group = splitTasksGroupInfo()
+        assertThat(group.taskInfo1.taskId).isEqualTo(1)
+        assertThat(group.taskInfo2?.taskId).isEqualTo(2)
+        assertThat(group.splitBounds).isNotNull()
+    }
+
+    @Test
+    fun testSplitTasks_taskInfoList_hasTwoTasks() {
+        val list = splitTasksGroupInfo().taskInfoList
+        assertThat(list).hasSize(2)
+        assertThat(list[0].taskId).isEqualTo(1)
+        assertThat(list[1].taskId).isEqualTo(2)
+    }
+
+    @Test
+    fun testFreeformTasks_hasCorrectType() {
+        assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM)
+    }
+
+    @Test
+    fun testSplitTasks_taskInfoList_hasThreeTasks() {
+        val list = freeformTasksGroupInfo().taskInfoList
+        assertThat(list).hasSize(3)
+        assertThat(list[0].taskId).isEqualTo(1)
+        assertThat(list[1].taskId).isEqualTo(2)
+        assertThat(list[2].taskId).isEqualTo(3)
+    }
+
+    @Test
+    fun testParcelling_singleTask() {
+        val recentTaskInfo = singleTaskGroupInfo()
+        val parcel = Parcel.obtain()
+        recentTaskInfo.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+        // Read the object back from the parcel
+        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SINGLE)
+        assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+        assertThat(recentTaskInfoParcel.taskInfo2).isNull()
+    }
+
+    @Test
+    fun testParcelling_splitTasks() {
+        val recentTaskInfo = splitTasksGroupInfo()
+        val parcel = Parcel.obtain()
+        recentTaskInfo.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+        // Read the object back from the parcel
+        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SPLIT)
+        assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+        assertThat(recentTaskInfoParcel.taskInfo2).isNotNull()
+        assertThat(recentTaskInfoParcel.taskInfo2!!.taskId).isEqualTo(2)
+        assertThat(recentTaskInfoParcel.splitBounds).isNotNull()
+    }
+
+    @Test
+    fun testParcelling_freeformTasks() {
+        val recentTaskInfo = freeformTasksGroupInfo()
+        val parcel = Parcel.obtain()
+        recentTaskInfo.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+        // Read the object back from the parcel
+        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM)
+        assertThat(recentTaskInfoParcel.taskInfoList).hasSize(3)
+        // Only compare task ids
+        val taskIdComparator = Correspondence.transforming<ActivityManager.RecentTaskInfo, Int>(
+            { it?.taskId }, "has taskId of"
+        )
+        assertThat(recentTaskInfoParcel.taskInfoList).comparingElementsUsing(taskIdComparator)
+            .containsExactly(1, 2, 3)
+    }
+
+    private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
+        taskId = id
+        token = WindowContainerToken(mock(IWindowContainerToken::class.java))
+    }
+
+    private fun singleTaskGroupInfo(): GroupedRecentTaskInfo {
+        val task = createTaskInfo(id = 1)
+        return GroupedRecentTaskInfo.forSingleTask(task)
+    }
+
+    private fun splitTasksGroupInfo(): GroupedRecentTaskInfo {
+        val task1 = createTaskInfo(id = 1)
+        val task2 = createTaskInfo(id = 2)
+        val splitBounds = SplitBounds(Rect(), Rect(), 1, 2)
+        return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds)
+    }
+
+    private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo {
+        val task1 = createTaskInfo(id = 1)
+        val task2 = createTaskInfo(id = 2)
+        val task3 = createTaskInfo(id = 3)
+        return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 81bb609..e9a1e25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -20,6 +20,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -45,11 +48,13 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
@@ -179,6 +184,46 @@
     }
 
     @Test
+    public void testGetRecentTasks_groupActiveFreeformTasks() {
+        StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
+                DesktopMode.class).startMocking();
+        when(DesktopMode.isActive(any())).thenReturn(true);
+
+        ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+        ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+        ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+        ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
+        setRawList(t1, t2, t3, t4);
+
+        mRecentTasksController.addActiveFreeformTask(1);
+        mRecentTasksController.addActiveFreeformTask(3);
+
+        ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
+                MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+
+        // 2 freeform tasks should be grouped into one, 3 total recents entries
+        assertEquals(3, recentTasks.size());
+        GroupedRecentTaskInfo freeformGroup = recentTasks.get(0);
+        GroupedRecentTaskInfo singleGroup1 = recentTasks.get(1);
+        GroupedRecentTaskInfo singleGroup2 = recentTasks.get(2);
+
+        // Check that groups have expected types
+        assertEquals(GroupedRecentTaskInfo.TYPE_FREEFORM, freeformGroup.getType());
+        assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup1.getType());
+        assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup2.getType());
+
+        // Check freeform group entries
+        assertEquals(t1, freeformGroup.getTaskInfoList().get(0));
+        assertEquals(t3, freeformGroup.getTaskInfoList().get(1));
+
+        // Check single entries
+        assertEquals(t2, singleGroup1.getTaskInfo1());
+        assertEquals(t4, singleGroup2.getTaskInfo1());
+
+        mockitoSession.finishMocking();
+    }
+
+    @Test
     public void testRemovedTaskRemovesSplit() {
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -254,6 +299,7 @@
 
     /**
      * Asserts that the recent tasks matches the given task ids.
+     *
      * @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
      *                        the grouped task list
      */
@@ -262,22 +308,23 @@
         int[] flattenedTaskIds = new int[recentTasks.size() * 2];
         for (int i = 0; i < recentTasks.size(); i++) {
             GroupedRecentTaskInfo pair = recentTasks.get(i);
-            int taskId1 = pair.mTaskInfo1.taskId;
+            int taskId1 = pair.getTaskInfo1().taskId;
             flattenedTaskIds[2 * i] = taskId1;
-            flattenedTaskIds[2 * i + 1] = pair.mTaskInfo2 != null
-                    ? pair.mTaskInfo2.taskId
+            flattenedTaskIds[2 * i + 1] = pair.getTaskInfo2() != null
+                    ? pair.getTaskInfo2().taskId
                     : -1;
 
-            if (pair.mTaskInfo2 != null) {
-                assertNotNull(pair.mSplitBounds);
-                int leftTopTaskId = pair.mSplitBounds.leftTopTaskId;
-                int bottomRightTaskId = pair.mSplitBounds.rightBottomTaskId;
+            if (pair.getTaskInfo2() != null) {
+                assertNotNull(pair.getSplitBounds());
+                int leftTopTaskId = pair.getSplitBounds().leftTopTaskId;
+                int bottomRightTaskId = pair.getSplitBounds().rightBottomTaskId;
                 // Unclear if pairs are ordered by split position, most likely not.
-                assertTrue(leftTopTaskId == taskId1 || leftTopTaskId == pair.mTaskInfo2.taskId);
+                assertTrue(leftTopTaskId == taskId1
+                        || leftTopTaskId == pair.getTaskInfo2().taskId);
                 assertTrue(bottomRightTaskId == taskId1
-                        || bottomRightTaskId == pair.mTaskInfo2.taskId);
+                        || bottomRightTaskId == pair.getTaskInfo2().taskId);
             } else {
-                assertNull(pair.mSplitBounds);
+                assertNull(pair.getSplitBounds());
             }
         }
         assertTrue("Expected: " + Arrays.toString(expectedTaskIds)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index a67853c..ae69b3d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -71,11 +71,11 @@
                 DisplayController displayController, DisplayImeController imeController,
                 DisplayInsetsController insetsController, SplitLayout splitLayout,
                 Transitions transitions, TransactionPool transactionPool,
-                SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+                ShellExecutor mainExecutor,
                 Optional<RecentTasksController> recentTasks) {
             super(context, displayId, syncQueue, taskOrganizer, mainStage,
                     sideStage, displayController, imeController, insetsController, splitLayout,
-                    transitions, transactionPool, logger, mainExecutor, recentTasks);
+                    transitions, transactionPool, mainExecutor, recentTasks);
 
             // Prepare root task for testing.
             mRootTask = new TestRunningTaskInfoBuilder().build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 1d038f4..ea0033b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -95,7 +95,6 @@
     @Mock private TransactionPool mTransactionPool;
     @Mock private Transitions mTransitions;
     @Mock private SurfaceSession mSurfaceSession;
-    @Mock private SplitscreenEventLogger mLogger;
     @Mock private IconProvider mIconProvider;
     @Mock private ShellExecutor mMainExecutor;
     private SplitLayout mSplitLayout;
@@ -127,7 +126,7 @@
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
                 mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
                 mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
-                mTransactionPool, mLogger, mMainExecutor, Optional.empty());
+                mTransactionPool, mMainExecutor, Optional.empty());
         mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
         doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
                 .when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 4b68870..9240abf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -97,8 +97,6 @@
     @Mock
     private TransactionPool mTransactionPool;
     @Mock
-    private SplitscreenEventLogger mLogger;
-    @Mock
     private ShellExecutor mMainExecutor;
 
     private final Rect mBounds1 = new Rect(10, 20, 30, 40);
@@ -115,7 +113,7 @@
         MockitoAnnotations.initMocks(this);
         mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                 mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
-                mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mLogger,
+                mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
                 mMainExecutor, Optional.empty()));
         doNothing().when(mStageCoordinator).updateActivityOptions(any(), anyInt());
 
@@ -227,7 +225,6 @@
         mStageCoordinator.exitSplitScreen(testTaskId, EXIT_REASON_RETURN_HOME);
         verify(mMainStage).reorderChild(eq(testTaskId), eq(true),
                 any(WindowContainerTransaction.class));
-        verify(mSideStage).dismiss(any(WindowContainerTransaction.class), eq(false));
         verify(mMainStage).resetBounds(any(WindowContainerTransaction.class));
     }
 
@@ -241,7 +238,6 @@
         verify(mSideStage).reorderChild(eq(testTaskId), eq(true),
                 any(WindowContainerTransaction.class));
         verify(mSideStage).resetBounds(any(WindowContainerTransaction.class));
-        verify(mMainStage).dismiss(any(WindowContainerTransaction.class), eq(false));
     }
 
     @Test
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 39c7d19..235700b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -601,10 +601,6 @@
     return base::unexpected(result.error());
   }
 
-  if (type_idx == 0x1c) {
-    LOG(ERROR) << base::StringPrintf("foobar first result %s", result->package_name->c_str());
-  }
-
   bool overlaid = false;
   if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
     for (const auto& id_map : package_group.overlays_) {
@@ -615,7 +611,21 @@
       }
       if (overlay_entry.IsInlineValue()) {
         // The target resource is overlaid by an inline value not represented by a resource.
-        result->entry = overlay_entry.GetInlineValue();
+        ConfigDescription best_frro_config;
+        Res_value best_frro_value;
+        bool frro_found = false;
+        for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
+          if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
+              && config.match(*desired_config)) {
+            frro_found = true;
+            best_frro_config = config;
+            best_frro_value = value;
+          }
+        }
+        if (!frro_found) {
+          continue;
+        }
+        result->entry = best_frro_value;
         result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
         result->cookie = id_map.cookie;
 
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index efd1f6a..e122d48 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -56,6 +56,8 @@
 struct Idmap_data_header {
   uint32_t target_entry_count;
   uint32_t target_inline_entry_count;
+  uint32_t target_inline_entry_value_count;
+  uint32_t configuration_count;
   uint32_t overlay_entry_count;
 
   uint32_t string_pool_index_offset;
@@ -68,6 +70,12 @@
 
 struct Idmap_target_entry_inline {
   uint32_t target_id;
+  uint32_t start_value_index;
+  uint32_t value_count;
+};
+
+struct Idmap_target_entry_inline_value {
+  uint32_t config_index;
   Res_value value;
 };
 
@@ -138,11 +146,15 @@
 IdmapResMap::IdmapResMap(const Idmap_data_header* data_header,
                          const Idmap_target_entry* entries,
                          const Idmap_target_entry_inline* inline_entries,
+                         const Idmap_target_entry_inline_value* inline_entry_values,
+                         const ConfigDescription* configs,
                          uint8_t target_assigned_package_id,
                          const OverlayDynamicRefTable* overlay_ref_table)
     : data_header_(data_header),
       entries_(entries),
       inline_entries_(inline_entries),
+      inline_entry_values_(inline_entry_values),
+      configurations_(configs),
       target_assigned_package_id_(target_assigned_package_id),
       overlay_ref_table_(overlay_ref_table) { }
 
@@ -183,7 +195,13 @@
 
   if (inline_entry != end_inline_entry &&
       (0x00FFFFFFU & dtohl(inline_entry->target_id)) == target_res_id) {
-    return Result(inline_entry->value);
+    std::map<ConfigDescription, Res_value> values_map;
+    for (int i = 0; i < inline_entry->value_count; i++) {
+      const auto& value = inline_entry_values_[inline_entry->start_value_index + i];
+      const auto& config = configurations_[value.config_index];
+      values_map[config] = value.value;
+    }
+    return Result(values_map);
   }
   return {};
 }
@@ -237,6 +255,8 @@
                          const Idmap_data_header* data_header,
                          const Idmap_target_entry* target_entries,
                          const Idmap_target_entry_inline* target_inline_entries,
+                         const Idmap_target_entry_inline_value* inline_entry_values,
+                         const ConfigDescription* configs,
                          const Idmap_overlay_entry* overlay_entries,
                          std::unique_ptr<ResStringPool>&& string_pool,
                          std::string_view overlay_apk_path,
@@ -245,6 +265,8 @@
        data_header_(data_header),
        target_entries_(target_entries),
        target_inline_entries_(target_inline_entries),
+       inline_entry_values_(inline_entry_values),
+       configurations_(configs),
        overlay_entries_(overlay_entries),
        string_pool_(std::move(string_pool)),
        idmap_path_(std::move(idmap_path)),
@@ -303,6 +325,21 @@
   if (target_inline_entries == nullptr) {
     return {};
   }
+
+  auto target_inline_entry_values = ReadType<Idmap_target_entry_inline_value>(
+      &data_ptr, &data_size, "target inline values",
+      dtohl(data_header->target_inline_entry_value_count));
+  if (target_inline_entry_values == nullptr) {
+    return {};
+  }
+
+  auto configurations = ReadType<ConfigDescription>(
+      &data_ptr, &data_size, "configurations",
+      dtohl(data_header->configuration_count));
+  if (configurations == nullptr) {
+    return {};
+  }
+
   auto overlay_entries = ReadType<Idmap_overlay_entry>(&data_ptr, &data_size, "target inline",
                                                        dtohl(data_header->overlay_entry_count));
   if (overlay_entries == nullptr) {
@@ -329,8 +366,8 @@
   // Can't use make_unique because LoadedIdmap constructor is private.
   return std::unique_ptr<LoadedIdmap>(
       new LoadedIdmap(idmap_path.to_string(), header, data_header, target_entries,
-                      target_inline_entries, overlay_entries, std::move(idmap_string_pool),
-                      *target_path, *overlay_path));
+                      target_inline_entries, target_inline_entry_values, configurations,
+                      overlay_entries, std::move(idmap_string_pool), *target_path, *overlay_path));
 }
 
 bool LoadedIdmap::IsUpToDate() const {
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index 6804472..a1cbbbf 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -23,6 +23,7 @@
 #include <variant>
 
 #include "android-base/macros.h"
+#include "androidfw/ConfigDescription.h"
 #include "androidfw/StringPiece.h"
 #include "androidfw/ResourceTypes.h"
 #include "utils/ByteOrder.h"
@@ -35,6 +36,7 @@
 struct Idmap_data_header;
 struct Idmap_target_entry;
 struct Idmap_target_entry_inline;
+struct Idmap_target_entry_inline_value;
 struct Idmap_overlay_entry;
 
 // A string pool for overlay apk assets. The string pool holds the strings of the overlay resources
@@ -91,7 +93,8 @@
    public:
     Result() = default;
     explicit Result(uint32_t value) : data_(value) {};
-    explicit Result(const Res_value& value) : data_(value) { };
+    explicit Result(const std::map<ConfigDescription, Res_value> &value)
+        : data_(value) { };
 
     // Returns `true` if the resource is overlaid.
     explicit operator bool() const {
@@ -107,15 +110,16 @@
     }
 
     bool IsInlineValue() const {
-      return std::get_if<Res_value>(&data_) != nullptr;
+      return std::get_if<2>(&data_) != nullptr;
     }
 
-    const Res_value& GetInlineValue() const {
-      return std::get<Res_value>(data_);
+    const std::map<ConfigDescription, Res_value>& GetInlineValue() const {
+      return std::get<2>(data_);
     }
 
    private:
-      std::variant<std::monostate, uint32_t, Res_value> data_;
+      std::variant<std::monostate, uint32_t,
+          std::map<ConfigDescription, Res_value> > data_;
   };
 
   // Looks up the value that overlays the target resource id.
@@ -129,12 +133,16 @@
   explicit IdmapResMap(const Idmap_data_header* data_header,
                        const Idmap_target_entry* entries,
                        const Idmap_target_entry_inline* inline_entries,
+                       const Idmap_target_entry_inline_value* inline_entry_values,
+                       const ConfigDescription* configs,
                        uint8_t target_assigned_package_id,
                        const OverlayDynamicRefTable* overlay_ref_table);
 
   const Idmap_data_header* data_header_;
   const Idmap_target_entry* entries_;
   const Idmap_target_entry_inline* inline_entries_;
+  const Idmap_target_entry_inline_value* inline_entry_values_;
+  const ConfigDescription* configurations_;
   const uint8_t target_assigned_package_id_;
   const OverlayDynamicRefTable* overlay_ref_table_;
 
@@ -170,8 +178,8 @@
   // Returns a mapping from target resource ids to overlay values.
   const IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id,
                                           const OverlayDynamicRefTable* overlay_ref_table) const {
-    return IdmapResMap(data_header_, target_entries_, target_inline_entries_,
-                       target_assigned_package_id, overlay_ref_table);
+    return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_,
+                       configurations_, target_assigned_package_id, overlay_ref_table);
   }
 
   // Returns a dynamic reference table for a loaded overlay package.
@@ -191,6 +199,8 @@
   const Idmap_data_header* data_header_;
   const Idmap_target_entry* target_entries_;
   const Idmap_target_entry_inline* target_inline_entries_;
+  const Idmap_target_entry_inline_value* inline_entry_values_;
+  const ConfigDescription* configurations_;
   const Idmap_overlay_entry* overlay_entries_;
   const std::unique_ptr<ResStringPool> string_pool_;
 
@@ -207,6 +217,8 @@
                        const Idmap_data_header* data_header,
                        const Idmap_target_entry* target_entries,
                        const Idmap_target_entry_inline* target_inline_entries,
+                       const Idmap_target_entry_inline_value* inline_entry_values_,
+                       const ConfigDescription* configs,
                        const Idmap_overlay_entry* overlay_entries,
                        std::unique_ptr<ResStringPool>&& string_pool,
                        std::string_view overlay_apk_path,
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 8c614bc..9309091 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -45,7 +45,7 @@
 namespace android {
 
 constexpr const uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const uint32_t kIdmapCurrentVersion = 0x00000008u;
+constexpr const uint32_t kIdmapCurrentVersion = 0x00000009u;
 
 // This must never change.
 constexpr const uint32_t kFabricatedOverlayMagic = 0x4f525246; // FRRO (big endian)
@@ -1098,7 +1098,7 @@
         SDKVERSION_ANY = 0
     };
     
-  enum {
+    enum {
         MINORVERSION_ANY = 0
     };
     
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 88eadcc..8e847e8 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 397975d..473afbd 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -18,6 +18,7 @@
 
 #include "CanvasProperty.h"
 #include "NinePatchUtils.h"
+#include "SkBlendMode.h"
 #include "VectorDrawable.h"
 #include "hwui/Bitmap.h"
 #include "hwui/MinikinUtils.h"
@@ -251,10 +252,11 @@
     return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
 }
 
-void SkiaCanvas::punchHole(const SkRRect& rect) {
+void SkiaCanvas::punchHole(const SkRRect& rect, float alpha) {
     SkPaint paint = SkPaint();
-    paint.setColor(0);
-    paint.setBlendMode(SkBlendMode::kClear);
+    paint.setColor(SkColors::kBlack);
+    paint.setAlphaf(alpha);
+    paint.setBlendMode(SkBlendMode::kDstOut);
     mCanvas->drawRRect(rect, paint);
 }
 
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index c6313f6..51007c5 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -65,7 +65,7 @@
         LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
     }
 
-    virtual void punchHole(const SkRRect& rect) override;
+    virtual void punchHole(const SkRRect& rect, float alpha) override;
 
     virtual void setBitmap(const SkBitmap& bitmap) override;
 
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 7378351..82d23b5 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -152,7 +152,7 @@
         LOG_ALWAYS_FATAL("Not supported");
     }
 
-    virtual void punchHole(const SkRRect& rect) = 0;
+    virtual void punchHole(const SkRRect& rect, float alpha) = 0;
 
     // ----------------------------------------------------------------------------
     // Canvas state operations
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index fb7d5f7..0513447 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -713,9 +713,10 @@
 }
 
 static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
-        jfloat bottom, jfloat rx, jfloat ry) {
+        jfloat bottom, jfloat rx, jfloat ry, jfloat alpha) {
     auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
-    canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
+    canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry),
+                      alpha);
 }
 
 }; // namespace CanvasJNI
@@ -790,7 +791,7 @@
     {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
     {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
     {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
-    {"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
+    {"nPunchHole", "(JFFFFFFF)V", (void*) CanvasJNI::punchHole}
 };
 
 int register_android_graphics_Canvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 3bf2b2e..f2282e66 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -201,6 +201,7 @@
         paint.setAlpha((uint8_t)paint.getAlpha() * mAlpha);
         return true;
     }
+
     void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
         // We unroll the drawable using "this" canvas, so that draw calls contained inside will
         // get their alpha applied. The default SkPaintFilterCanvas::onDrawDrawable does not unroll.
@@ -292,7 +293,7 @@
                 // with the same canvas transformation + clip into the target
                 // canvas then draw the layer on top
                 if (renderNode->hasHolePunches()) {
-                    TransformCanvas transformCanvas(canvas, SkBlendMode::kClear);
+                    TransformCanvas transformCanvas(canvas, SkBlendMode::kDstOut);
                     displayList->draw(&transformCanvas);
                 }
                 canvas->drawImageRect(snapshotImage, SkRect::Make(srcBounds),
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 5c6117d..1f87865 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -69,20 +69,22 @@
     mDisplayList->setHasHolePunches(false);
 }
 
-void SkiaRecordingCanvas::punchHole(const SkRRect& rect) {
-    // Add the marker annotation to allow HWUI to determine where the current
-    // clip/transformation should be applied
+void SkiaRecordingCanvas::punchHole(const SkRRect& rect, float alpha) {
+    // Add the marker annotation to allow HWUI to determine the current
+    // clip/transformation and alpha should be applied
     SkVector vector = rect.getSimpleRadii();
-    float data[2];
+    float data[3];
     data[0] = vector.x();
     data[1] = vector.y();
+    data[2] = alpha;
     mRecorder.drawAnnotation(rect.rect(), HOLE_PUNCH_ANNOTATION.c_str(),
-                             SkData::MakeWithCopy(data, 2 * sizeof(float)));
+                             SkData::MakeWithCopy(data, sizeof(data)));
 
     // Clear the current rect within the layer itself
     SkPaint paint = SkPaint();
-    paint.setColor(0);
-    paint.setBlendMode(SkBlendMode::kClear);
+    paint.setColor(SkColors::kBlack);
+    paint.setAlphaf(alpha);
+    paint.setBlendMode(SkBlendMode::kDstOut);
     mRecorder.drawRRect(rect, paint);
 
     mDisplayList->setHasHolePunches(true);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 89e3a2c..7844e2c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -50,7 +50,7 @@
         initDisplayList(renderNode, width, height);
     }
 
-    virtual void punchHole(const SkRRect& rect) override;
+    virtual void punchHole(const SkRRect& rect, float alpha) override;
 
     virtual void finishRecording(uirenderer::RenderNode* destination) override;
     std::unique_ptr<SkiaDisplayList> finishRecording();
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
index 33160d0..c320df0 100644
--- a/libs/hwui/pipeline/skia/TransformCanvas.cpp
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -29,13 +29,15 @@
 void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) {
     if (HOLE_PUNCH_ANNOTATION == key) {
         auto* rectParams = reinterpret_cast<const float*>(value->data());
-        float radiusX = rectParams[0];
-        float radiusY = rectParams[1];
+        const float radiusX = rectParams[0];
+        const float radiusY = rectParams[1];
+        const float alpha = rectParams[2];
         SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);
 
         SkPaint paint;
         paint.setColor(SkColors::kBlack);
         paint.setBlendMode(mHolePunchBlendMode);
+        paint.setAlphaf(alpha);
         mWrappedCanvas->drawRRect(roundRect, paint);
     }
 }
diff --git a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
index 59230a7..7d3ca96 100644
--- a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
@@ -138,7 +138,7 @@
         roundRectPaint.setColor(Color::White);
         if (addHolePunch) {
             // Punch a hole but then cover it up, we don't want to actually see it
-            canvas.punchHole(SkRRect::MakeRect(SkRect::MakeWH(itemWidth, itemHeight)));
+            canvas.punchHole(SkRRect::MakeRect(SkRect::MakeWH(itemWidth, itemHeight)), 1.f);
         }
         canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
 
@@ -235,4 +235,4 @@
     StretchEffectBehavior stretchBehavior() override { return StretchEffectBehavior::UniformScale; }
     bool haveHolePunch() override { return true; }
     bool forceLayer() override { return true; }
-};
\ No newline at end of file
+};
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 60c812a..819358b 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -677,21 +677,39 @@
 
     @Override
     public String toString() {
-        return "AudioPlaybackConfiguration piid:" + mPlayerIId
-                + " deviceId:" + mDeviceId
-                + " type:" + toLogFriendlyPlayerType(mPlayerType)
-                + " u/pid:" + mClientUid + "/" + mClientPid
-                + " state:" + toLogFriendlyPlayerState(mPlayerState)
-                + " attr:" + mPlayerAttr
-                + " sessionId:" + mSessionId
-                + " mutedState:"
-                + " muteFromMasterMute=" + ((mMutedState & PLAYER_MUTE_MASTER) != 0)
-                + " muteFromStreamVolume=" + ((mMutedState & PLAYER_MUTE_STREAM_VOLUME) != 0)
-                + " muteFromStreamMuted=" + ((mMutedState & PLAYER_MUTE_STREAM_MUTED) != 0)
-                + " muteFromPlaybackRestricted=" + ((mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED)
-                != 0)
-                + " muteFromClientVolume=" + ((mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0)
-                + " muteFromVolumeShaper=" + ((mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0);
+        StringBuilder apcToString = new StringBuilder();
+        apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append(
+                " deviceId:").append(mDeviceId).append(" type:").append(
+                toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append(mClientUid).append(
+                "/").append(mClientPid).append(" state:").append(
+                toLogFriendlyPlayerState(mPlayerState)).append(" attr:").append(mPlayerAttr).append(
+                " sessionId:").append(mSessionId).append(" mutedState:");
+        if (mMutedState == PLAYER_MUTE_INVALID) {
+            apcToString.append("invalid ");
+        } else if (mMutedState == 0) {
+            apcToString.append("none ");
+        } else {
+            if ((mMutedState & PLAYER_MUTE_MASTER) != 0) {
+                apcToString.append("master ");
+            }
+            if ((mMutedState & PLAYER_MUTE_STREAM_VOLUME) != 0) {
+                apcToString.append("streamVolume ");
+            }
+            if ((mMutedState & PLAYER_MUTE_STREAM_MUTED) != 0) {
+                apcToString.append("streamMute ");
+            }
+            if ((mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0) {
+                apcToString.append("playbackRestricted ");
+            }
+            if ((mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0) {
+                apcToString.append("clientVolume ");
+            }
+            if ((mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0) {
+                apcToString.append("volumeShaper ");
+            }
+        }
+
+        return apcToString.toString();
     }
 
     //=====================================================================
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 72190e3..6764890 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2383,6 +2383,14 @@
         return types.size() == 1 && types.contains(type);
     }
 
+    /**
+     * @hide
+     * Return true if the audio device type is a Bluetooth LE Audio device.
+     */
+    public static boolean isLeAudioDeviceType(int type) {
+        return DEVICE_OUT_ALL_BLE_SET.contains(type);
+    }
+
     /** @hide */
     public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
             (1 << STREAM_MUSIC) |
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index e18642c..0c8cacd 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -79,20 +79,24 @@
 /**
  * This is a class for reading and writing Exif tags in various image file formats.
  * <p>
+ * <b>Note:</b> This class has known issues on some versions of Android. It is recommended to use
+ * the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
+ * Library</a> since it offers a superset of the functionality of this class and is more easily
+ * updateable. In addition to the functionality of this class, it supports parsing extra metadata
+ * such as exposure and data compression information as well as setting extra metadata such as GPS
+ * and datetime information.
+ * <p>
  * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF,
  * AVIF.
  * <p>
- * Supported for writing: JPEG, PNG, WebP, DNG.
+ * Supported for writing: JPEG, PNG, WebP.
  * <p>
  * Note: JPEG and HEIF files may contain XMP data either inside the Exif data chunk or outside of
  * it. This class will search both locations for XMP data, but if XMP data exist both inside and
  * outside Exif, will favor the XMP data inside Exif over the one outside.
  * <p>
- * Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
- * Library</a> since it is a superset of this class. In addition to the functionalities of this
- * class, it supports parsing extra metadata such as exposure and data compression information
- * as well as setting extra metadata such as GPS and datetime information.
+
  */
 public class ExifInterface {
     private static final String TAG = "ExifInterface";
@@ -1294,7 +1298,6 @@
             new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
             new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
             new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
-            new ExifTag(TAG_XMP, 700, IFD_FORMAT_BYTE),
             new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
             new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
             new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
@@ -2076,7 +2079,7 @@
      * {@link #setAttribute(String,String)} to set all attributes to write and
      * make a single call rather than multiple calls for each attribute.
      * <p>
-     * This method is supported for JPEG, PNG, WebP, and DNG files.
+     * This method is supported for JPEG, PNG, and WebP files.
      * <p class="note">
      * Note: after calling this method, any attempts to obtain range information
      * from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
@@ -2088,11 +2091,15 @@
      * <p>
      * For PNG format, the Exif data will be stored as an "eXIf" chunk as per
      * "Extensions to the PNG 1.2 Specification, Version 1.5.0".
+     * <p>
+     * <b>Warning:</b> Calling this method on a DNG-based instance of {@code ExifInterface} may
+     * result in the original image file being overwritten with invalid data on some versions of
+     * Android 13 (API 33).
      */
     public void saveAttributes() throws IOException {
         if (!isSupportedFormatForSavingAttributes()) {
             throw new IOException("ExifInterface only supports saving attributes for JPEG, PNG, "
-                    + "WebP, and DNG formats.");
+                    + "and WebP formats.");
         }
         if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
             throw new IOException(
@@ -2150,10 +2157,6 @@
                     savePngAttributes(bufferedIn, bufferedOut);
                 } else if (mMimeType == IMAGE_TYPE_WEBP) {
                     saveWebpAttributes(bufferedIn, bufferedOut);
-                } else if (mMimeType == IMAGE_TYPE_DNG || mMimeType == IMAGE_TYPE_UNKNOWN) {
-                    ByteOrderedDataOutputStream dataOutputStream =
-                            new ByteOrderedDataOutputStream(bufferedOut, ByteOrder.BIG_ENDIAN);
-                    writeExifSegment(dataOutputStream);
                 }
             }
         } catch (Exception e) {
@@ -5262,8 +5265,7 @@
 
     private boolean isSupportedFormatForSavingAttributes() {
         if (mIsSupportedFile && (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_PNG
-                || mMimeType == IMAGE_TYPE_WEBP || mMimeType == IMAGE_TYPE_DNG
-                || mMimeType == IMAGE_TYPE_UNKNOWN)) {
+                || mMimeType == IMAGE_TYPE_WEBP)) {
             return true;
         }
         return false;
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index fde7afd..ca906d2 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -342,9 +342,14 @@
         // Only include memory for 1 buffer, since actually accounting for the memory used is
         // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
         // size.
-        mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
-            width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
-            /*buffer count*/ 1);
+        if (hardwareBufferFormat == HardwareBuffer.BLOB) {
+            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
+                width, height, imageFormat, /*buffer count*/ 1);
+        } else {
+            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
+                width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
+                /*buffer count*/ 1);
+        }
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
@@ -370,7 +375,6 @@
             MultiResolutionImageReader parent, int hardwareBufferFormat, int dataSpace) {
         mWidth = width;
         mHeight = height;
-        mFormat = ImageFormat.UNKNOWN; // set default image format value as UNKNOWN
         mUsage = usage;
         mMaxImages = maxImages;
         mParent = parent;
@@ -378,6 +382,7 @@
         mDataSpace = dataSpace;
         mUseLegacyImageFormat = false;
         mNumPlanes = ImageUtils.getNumPlanesForHardwareBufferFormat(mHardwareBufferFormat);
+        mFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
 
         initializeImageReader(width, height, mFormat, maxImages, usage, hardwareBufferFormat,
                 dataSpace, mUseLegacyImageFormat);
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 9f52bf1..259c138 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -29,7 +29,6 @@
 import android.hardware.HardwareBuffer;
 import android.hardware.HardwareBuffer.Usage;
 import android.hardware.SyncFence;
-import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -266,31 +265,11 @@
             // nativeInit internally overrides UNKNOWN format. So does surface format query after
             // nativeInit and before getEstimatedNativeAllocBytes().
             imageFormat = SurfaceUtils.getSurfaceFormat(surface);
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+            mDataSpace = dataSpace = PublicFormatUtils.getHalDataspace(dataSpace);
+            mHardwareBufferFormat =
+                hardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
         }
 
-        // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
-        // allocation estimation sequence depends on the public formats values. To avoid
-        // possible errors, convert where necessary.
-        if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
-            int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
-            switch (surfaceDataspace) {
-                case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
-                    imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
-                    break;
-                case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
-                    imageFormat = ImageFormat.DEPTH_JPEG;
-                    break;
-                case StreamConfigurationMap.HAL_DATASPACE_HEIF:
-                    imageFormat = ImageFormat.HEIC;
-                    break;
-                default:
-                    imageFormat = ImageFormat.JPEG;
-            }
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
-        }
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
         // itself and the buffers requested by the producer.
@@ -301,17 +280,44 @@
         mWidth = width == -1 ? surfSize.getWidth() : width;
         mHeight = height == -1 ? surfSize.getHeight() : height;
 
-        mEstimatedNativeAllocBytes =
-            ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
-                useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
+        if (hardwareBufferFormat == HardwareBuffer.BLOB) {
+            // TODO(b/246344817): remove mWriterFormat and mDataSpace re-set here after fixing.
+            mWriterFormat = imageFormat = getImageFormatByBLOB(dataSpace);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+
+            mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
+                imageFormat, /*buffer count*/ 1);
+        } else {
+            mEstimatedNativeAllocBytes =
+                ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
+                    useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
+        }
         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
     }
 
+    // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
+    // allocation estimation sequence depends on the public formats values. To avoid
+    // possible errors, convert where necessary.
+    private int getImageFormatByBLOB(int dataspace) {
+        switch (dataspace) {
+            case DataSpace.DATASPACE_DEPTH:
+                return ImageFormat.DEPTH_POINT_CLOUD;
+            case DataSpace.DATASPACE_DYNAMIC_DEPTH:
+                return ImageFormat.DEPTH_JPEG;
+            case DataSpace.DATASPACE_HEIF:
+                return ImageFormat.HEIC;
+            default:
+                return ImageFormat.JPEG;
+        }
+    }
+
     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
             int imageFormat, int width, int height) {
         mMaxImages = maxImages;
-        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-        mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        if (!useSurfaceImageFormatInfo) {
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
 
         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, mUsage);
@@ -321,8 +327,10 @@
             int imageFormat, int width, int height, long usage) {
         mMaxImages = maxImages;
         mUsage = usage;
-        mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-        mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        if (!useSurfaceImageFormatInfo) {
+            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+        }
 
         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, usage);
@@ -337,8 +345,6 @@
         // and retrieve corresponding hardwareBufferFormat and dataSpace here.
         if (useSurfaceImageFormatInfo) {
             imageFormat = ImageFormat.UNKNOWN;
-            mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
-            mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
         } else {
             imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
             mHardwareBufferFormat = hardwareBufferFormat;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 53d4efa..da2795f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3843,11 +3843,10 @@
     private void invalidateByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index, boolean input) {
         if (buffers == null) {
-            if (index < 0) {
-                throw new IllegalStateException("index is negative (" + index + ")");
+            if (index >= 0) {
+                BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+                indices.clear(index);
             }
-            BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
-            indices.clear(index);
         } else if (index >= 0 && index < buffers.length) {
             ByteBuffer buffer = buffers[index];
             if (buffer != null) {
@@ -3859,10 +3858,9 @@
     private void validateInputByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index) {
         if (buffers == null) {
-            if (index < 0) {
-                throw new IllegalStateException("index is negative (" + index + ")");
+            if (index >= 0) {
+                mValidInputIndices.set(index);
             }
-            mValidInputIndices.set(index);
         } else if (index >= 0 && index < buffers.length) {
             ByteBuffer buffer = buffers[index];
             if (buffer != null) {
@@ -3876,11 +3874,10 @@
             @Nullable ByteBuffer[] buffers, int index, boolean input) {
         synchronized(mBufferLock) {
             if (buffers == null) {
-                if (index < 0) {
-                    throw new IllegalStateException("index is negative (" + index + ")");
+                if (index >= 0) {
+                    BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
+                    indices.set(index);
                 }
-                BitSet indices = input ? mValidInputIndices : mValidOutputIndices;
-                indices.set(index);
             } else if (index >= 0 && index < buffers.length) {
                 ByteBuffer buffer = buffers[index];
                 if (buffer != null) {
@@ -3893,10 +3890,9 @@
     private void validateOutputByteBufferLocked(
             @Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
         if (buffers == null) {
-            if (index < 0) {
-                throw new IllegalStateException("index is negative (" + index + ")");
+            if (index >= 0) {
+                mValidOutputIndices.set(index);
             }
-            mValidOutputIndices.set(index);
         } else if (index >= 0 && index < buffers.length) {
             ByteBuffer buffer = buffers[index];
             if (buffer != null) {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 6317320..aeb81c1 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -696,6 +696,13 @@
         baseRegisterPlayer(sessionId);
     }
 
+    private Parcel createPlayerIIdParcel() {
+        Parcel parcel = newRequest();
+        parcel.writeInt(INVOKE_ID_SET_PLAYER_IID);
+        parcel.writeInt(mPlayerIId);
+        return parcel;
+    }
+
     /*
      * Update the MediaPlayer SurfaceTexture.
      * Call after setting a new display surface.
@@ -712,6 +719,7 @@
     private static final int INVOKE_ID_DESELECT_TRACK = 5;
     private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6;
     private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
+    private static final int INVOKE_ID_SET_PLAYER_IID = 8;
 
     /**
      * Create a request parcel which can be routed to the native media
@@ -1309,16 +1317,26 @@
      * @throws IllegalStateException if it is called in an invalid state
      */
     public void prepare() throws IOException, IllegalStateException {
-        _prepare();
+        Parcel piidParcel = createPlayerIIdParcel();
+        try {
+            int retCode = _prepare(piidParcel);
+            if (retCode != 0) {
+                Log.w(TAG, "prepare(): could not set piid " + mPlayerIId);
+            }
+        } finally {
+            piidParcel.recycle();
+        }
         scanInternalSubtitleTracks();
 
         // DrmInfo, if any, has been resolved by now.
         synchronized (mDrmLock) {
             mDrmInfoResolved = true;
         }
+
     }
 
-    private native void _prepare() throws IOException, IllegalStateException;
+    /** Returns the result of sending the {@code piidParcel} to the MediaPlayerService. */
+    private native int _prepare(Parcel piidParcel) throws IOException, IllegalStateException;
 
     /**
      * Prepares the player for playback, asynchronously.
@@ -1330,7 +1348,20 @@
      *
      * @throws IllegalStateException if it is called in an invalid state
      */
-    public native void prepareAsync() throws IllegalStateException;
+    public void prepareAsync() throws IllegalStateException {
+        Parcel piidParcel = createPlayerIIdParcel();
+        try {
+            int retCode = _prepareAsync(piidParcel);
+            if (retCode != 0) {
+                Log.w(TAG, "prepareAsync(): could not set piid " + mPlayerIId);
+            }
+        } finally {
+            piidParcel.recycle();
+        }
+    }
+
+    /** Returns the result of sending the {@code piidParcel} to the MediaPlayerService. */
+    private native int _prepareAsync(Parcel piidParcel) throws IllegalStateException;
 
     /**
      * Starts or resumes playback. If playback had previously been paused,
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index d7fc205..2e7896e 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -221,7 +221,7 @@
                 } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
                     name = R.string.default_audio_route_name_dock_speakers;
                 } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
-                    name = R.string.default_audio_route_name_hdmi;
+                    name = R.string.default_audio_route_name_external_device;
                 } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_USB) != 0) {
                     name = R.string.default_audio_route_name_usb;
                 } else {
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 86a94a9..82c3139 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -29,11 +29,12 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.provider.MediaStore;
 import android.provider.MediaStore.MediaColumns;
 import android.provider.Settings;
 import android.util.Log;
-
+import com.android.internal.annotations.VisibleForTesting;
 import java.io.IOException;
 import java.util.ArrayList;
 
@@ -136,13 +137,73 @@
      */
     public void setAudioAttributes(AudioAttributes attributes)
             throws IllegalArgumentException {
+        setAudioAttributesField(attributes);
+        // The audio attributes have to be set before the media player is prepared.
+        // Re-initialize it.
+        setUri(mUri, mVolumeShaperConfig);
+        createLocalMediaPlayer();
+    }
+
+    /**
+     * Same as {@link #setAudioAttributes(AudioAttributes)} except this one does not create
+     * the media player.
+     * @hide
+     */
+    public void setAudioAttributesField(@Nullable AudioAttributes attributes) {
         if (attributes == null) {
             throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone");
         }
         mAudioAttributes = attributes;
-        // The audio attributes have to be set before the media player is prepared.
-        // Re-initialize it.
-        setUri(mUri, mVolumeShaperConfig);
+    }
+
+    /**
+     * Creates a local media player for the ringtone using currently set attributes.
+     * @hide
+     */
+    public void createLocalMediaPlayer() {
+        Trace.beginSection("createLocalMediaPlayer");
+        if (mUri == null) {
+            Log.e(TAG, "Could not create media player as no URI was provided.");
+            return;
+        }
+        destroyLocalPlayer();
+        // try opening uri locally before delegating to remote player
+        mLocalPlayer = new MediaPlayer();
+        try {
+            mLocalPlayer.setDataSource(mContext, mUri);
+            mLocalPlayer.setAudioAttributes(mAudioAttributes);
+            synchronized (mPlaybackSettingsLock) {
+                applyPlaybackProperties_sync();
+            }
+            if (mVolumeShaperConfig != null) {
+                mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig);
+            }
+            mLocalPlayer.prepare();
+
+        } catch (SecurityException | IOException e) {
+            destroyLocalPlayer();
+            if (!mAllowRemote) {
+                Log.w(TAG, "Remote playback not allowed: " + e);
+            }
+        }
+
+        if (LOGD) {
+            if (mLocalPlayer != null) {
+                Log.d(TAG, "Successfully created local player");
+            } else {
+                Log.d(TAG, "Problem opening; delegating to remote player");
+            }
+        }
+        Trace.endSection();
+    }
+
+    /**
+     * Returns whether a local player has been created for this ringtone.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean hasLocalPlayer() {
+        return mLocalPlayer != null;
     }
 
     /**
@@ -336,8 +397,7 @@
     }
 
     /**
-     * Set {@link Uri} to be used for ringtone playback. Attempts to open
-     * locally, otherwise will delegate playback to remote
+     * Set {@link Uri} to be used for ringtone playback.
      * {@link IRingtonePlayer}.
      *
      * @hide
@@ -348,6 +408,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setVolumeShaperConfig(@Nullable VolumeShaper.Configuration volumeShaperConfig) {
+        mVolumeShaperConfig = volumeShaperConfig;
+    }
+
+    /**
      * Set {@link Uri} to be used for ringtone playback. Attempts to open
      * locally, otherwise will delegate playback to remote
      * {@link IRingtonePlayer}. Add {@link VolumeShaper} if required.
@@ -356,41 +423,10 @@
      */
     public void setUri(Uri uri, @Nullable VolumeShaper.Configuration volumeShaperConfig) {
         mVolumeShaperConfig = volumeShaperConfig;
-        destroyLocalPlayer();
 
         mUri = uri;
         if (mUri == null) {
-            return;
-        }
-
-        // TODO: detect READ_EXTERNAL and specific content provider case, instead of relying on throwing
-
-        // try opening uri locally before delegating to remote player
-        mLocalPlayer = new MediaPlayer();
-        try {
-            mLocalPlayer.setDataSource(mContext, mUri);
-            mLocalPlayer.setAudioAttributes(mAudioAttributes);
-            synchronized (mPlaybackSettingsLock) {
-                applyPlaybackProperties_sync();
-            }
-            if (mVolumeShaperConfig != null) {
-                mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig);
-            }
-            mLocalPlayer.prepare();
-
-        } catch (SecurityException | IOException e) {
             destroyLocalPlayer();
-            if (!mAllowRemote) {
-                Log.w(TAG, "Remote playback not allowed: " + e);
-            }
-        }
-
-        if (LOGD) {
-            if (mLocalPlayer != null) {
-                Log.d(TAG, "Successfully created local player");
-            } else {
-                Log.d(TAG, "Problem opening; delegating to remote player");
-            }
         }
     }
 
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 2772769..27db41c 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -480,8 +480,9 @@
         if (mStopPreviousRingtone && mPreviousRingtone != null) {
             mPreviousRingtone.stop();
         }
-        
-        mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType());
+
+        mPreviousRingtone =
+                getRingtone(mContext, getRingtoneUri(position), inferStreamType(), true);
         return mPreviousRingtone;
     }
 
@@ -677,7 +678,7 @@
      */
     public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
         // Don't set the stream type
-        return getRingtone(context, ringtoneUri, -1);
+        return getRingtone(context, ringtoneUri, -1, true);
     }
 
     /**
@@ -698,7 +699,34 @@
             final Context context, Uri ringtoneUri,
             @Nullable VolumeShaper.Configuration volumeShaperConfig) {
         // Don't set the stream type
-        return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig);
+        return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, true);
+    }
+
+    /**
+     * @hide
+     */
+    public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig,
+            boolean createLocalMediaPlayer) {
+        // Don't set the stream type
+        return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig,
+                createLocalMediaPlayer);
+    }
+
+    /**
+     * @hide
+     */
+    public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig,
+            AudioAttributes audioAttributes) {
+        // Don't set the stream type
+        Ringtone ringtone =
+                getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, false);
+        if (ringtone != null) {
+            ringtone.setAudioAttributesField(audioAttributes);
+            ringtone.createLocalMediaPlayer();
+        }
+        return ringtone;
     }
 
     //FIXME bypass the notion of stream types within the class
@@ -707,14 +735,19 @@
      * type. Normally, if you change the stream type on the returned
      * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just
      * an optimized route to avoid that.
-     * 
+     *
      * @param streamType The stream type for the ringtone, or -1 if it should
      *            not be set (and the default used instead).
+     * @param createLocalMediaPlayer when true, the ringtone returned will be fully
+     *      created otherwise, it will require the caller to create the media player manually
+     *      {@link Ringtone#createLocalMediaPlayer()} in order to play the Ringtone.
      * @see #getRingtone(Context, Uri)
      */
     @UnsupportedAppUsage
-    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
-        return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */);
+    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
+            boolean createLocalMediaPlayer) {
+        return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */,
+                createLocalMediaPlayer);
     }
 
     //FIXME bypass the notion of stream types within the class
@@ -730,16 +763,21 @@
      * @see #getRingtone(Context, Uri)
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private static Ringtone getRingtone(
-            final Context context, Uri ringtoneUri, int streamType,
-            @Nullable VolumeShaper.Configuration volumeShaperConfig) {
+    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig,
+            boolean createLocalMediaPlayer) {
         try {
             final Ringtone r = new Ringtone(context, true);
             if (streamType >= 0) {
                 //FIXME deprecated call
                 r.setStreamType(streamType);
             }
+
+            r.setVolumeShaperConfig(volumeShaperConfig);
             r.setUri(ringtoneUri, volumeShaperConfig);
+            if (createLocalMediaPlayer) {
+                r.createLocalMediaPlayer();
+            }
             return r;
         } catch (Exception ex) {
             Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex);
diff --git a/media/java/android/media/projection/MediaProjectionGlobal.java b/media/java/android/media/projection/MediaProjectionGlobal.java
new file mode 100644
index 0000000..4374a05
--- /dev/null
+++ b/media/java/android/media/projection/MediaProjectionGlobal.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.projection;
+
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.IDisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.hardware.display.VirtualDisplayConfig;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.Surface;
+
+/**
+ * This is a helper for MediaProjection when requests are made from outside an application. This
+ * should only be used by processes running as shell as a way to capture recordings without being
+ * an application. The requests will fail if coming from any process that's not Shell.
+ * @hide
+ */
+@SystemApi
+public class MediaProjectionGlobal {
+    private static final Object sLock = new Object();
+    private static MediaProjectionGlobal sInstance;
+
+    /**
+     * @return The instance of {@link MediaProjectionGlobal}
+     */
+    @NonNull
+    public static MediaProjectionGlobal getInstance() {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                final IBinder displayBinder = ServiceManager.getService(Context.DISPLAY_SERVICE);
+                final IBinder packageBinder = ServiceManager.getService("package");
+                if (displayBinder != null && packageBinder != null) {
+                    sInstance = new MediaProjectionGlobal(
+                                    IDisplayManager.Stub.asInterface(displayBinder),
+                                    IPackageManager.Stub.asInterface(packageBinder));
+                }
+            }
+            return sInstance;
+        }
+    }
+
+    private final IDisplayManager mDm;
+    private final IPackageManager mPackageManager;
+
+    private MediaProjectionGlobal(IDisplayManager dm, IPackageManager packageManager) {
+        mDm = dm;
+        mPackageManager = packageManager;
+    }
+
+    /**
+     * Creates a VirtualDisplay that will mirror the content of displayIdToMirror
+     * @param name The name for the virtual display
+     * @param width The initial width for the virtual display
+     * @param height The initial height for the virtual display
+     * @param displayIdToMirror The displayId that will be mirrored into the virtual display.
+     * @return VirtualDisplay that can be used to update properties.
+     */
+    @Nullable
+    public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height,
+            int displayIdToMirror, @Nullable Surface surface) {
+
+        // Density doesn't matter since this virtual display is only used for mirroring.
+        VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+                height, 1 /* densityDpi */)
+                .setFlags(VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR)
+                .setDisplayIdToMirror(displayIdToMirror);
+        if (surface != null) {
+            builder.setSurface(surface);
+        }
+        VirtualDisplayConfig virtualDisplayConfig = builder.build();
+
+        String[] packages;
+        try {
+            packages = mPackageManager.getPackagesForUid(Process.myUid());
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+
+        // Just use the first one since it just needs to match the package when looking it up by
+        // calling UID in system server.
+        // The call may come from a rooted device, in that case the requesting uid will be root so
+        // it will not have any package name
+        String packageName = packages == null ? null : packages[0];
+        DisplayManagerGlobal.VirtualDisplayCallback
+                callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(null, null);
+        int displayId;
+        try {
+            displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, null,
+                    packageName);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+        return DisplayManagerGlobal.getInstance().createVirtualDisplayWrapper(virtualDisplayConfig,
+                null, callbackWrapper, displayId);
+    }
+}
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 6c6fccb..fbc4bb9 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -1014,7 +1014,7 @@
     status_t res = lockImageFromBuffer(
             buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, noCrop, fenceFd, image);
     // Clear the fenceFd as it is already consumed by lock call.
-    Image_setFenceFd(env, thiz, /*fenceFd*/-1);
+    env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, -1);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
                 "lock buffer failed for format 0x%x",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index a548a47..da920bb 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -369,13 +369,13 @@
     setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
 }
 
-static void
-android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
+static jint
+android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz, jobject piidParcel)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
+    if (mp == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return;
+        return UNKNOWN_ERROR;
     }
 
     // Handle the case where the display surface was set before the mp was
@@ -384,15 +384,20 @@
     mp->setVideoSurfaceTexture(st);
 
     process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
+
+    // update the piid
+    Parcel *request = parcelForJavaObject(env, piidParcel);
+    auto reply = std::make_unique<Parcel>();
+    return static_cast<jint>(mp->invoke(*request, reply.get()));
 }
 
-static void
-android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
+static jint
+android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz, jobject piidParcel)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
+    if (mp == nullptr) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return;
+        return UNKNOWN_ERROR;
     }
 
     // Handle the case where the display surface was set before the mp was
@@ -401,6 +406,11 @@
     mp->setVideoSurfaceTexture(st);
 
     process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
+
+    // update the piid
+    Parcel *request = parcelForJavaObject(env, piidParcel);
+    auto reply = std::make_unique<Parcel>();
+    return static_cast<jint>(mp->invoke(*request, reply.get()));
 }
 
 static void
@@ -1380,8 +1390,8 @@
     {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
     {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
-    {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
-    {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
+    {"_prepare",            "(Landroid/os/Parcel;)I",           (void *)android_media_MediaPlayer_prepare},
+    {"_prepareAsync",       "(Landroid/os/Parcel;)I",           (void *)android_media_MediaPlayer_prepareAsync},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
     {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
     {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 2ddfacf..8b5b726 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -28,7 +28,7 @@
         "libaudioclient",
         "libaudioutils",
         "libaudiofoundation",
-        "libbinder"
+        "libbinder",
     ],
 
     export_shared_lib_headers: [
@@ -42,6 +42,7 @@
         "-Werror",
         "-Wunused",
         "-Wunreachable-code",
+        "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
 
     // Workaround Clang LTO crash.
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index d0f1ec6..09c45ea 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -142,7 +142,8 @@
     mCaptureRate = rate;
 
     if (cbk != NULL) {
-        mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
+        mCaptureThread = sp<CaptureThread>::make(
+                sp<Visualizer>::fromExisting(this), rate, ((flags & CAPTURE_CALL_JAVA) != 0));
     }
     ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
             rate, mCaptureThread.get(), mCaptureFlags);
@@ -439,7 +440,7 @@
 
 //-------------------------------------------------------------------------
 
-Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
+Visualizer::CaptureThread::CaptureThread(const sp<Visualizer>& receiver, uint32_t captureRate,
         bool bCanCallJava)
     : Thread(bCanCallJava), mReceiver(receiver)
 {
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index 3d5d74a..b38c01f 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -157,7 +157,8 @@
     class CaptureThread : public Thread
     {
     public:
-        CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
+        CaptureThread(const sp<Visualizer>& visualizer,
+                uint32_t captureRate, bool bCanCallJava = false);
 
     private:
         friend class Visualizer;
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 2fb85a7..63e48aa 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -205,15 +205,15 @@
     Mutex::Autolock l(sLock);
     AudioEffect* const ae =
             (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
-    return sp<AudioEffect>(ae);
+    return sp<AudioEffect>::fromExisting(ae);
 }
 
 static sp<AudioEffect> setAudioEffect(JNIEnv* env, jobject thiz,
                                     const sp<AudioEffect>& ae)
 {
     Mutex::Autolock l(sLock);
-    sp<AudioEffect> old =
-            (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
+    sp<AudioEffect> old = sp<AudioEffect>::fromExisting(
+            (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect));
     if (ae.get()) {
         ae->incStrong((void*)setAudioEffect);
     }
@@ -347,8 +347,8 @@
     // create the native AudioEffect object
     parcel = parcelForJavaObject(env, jAttributionSource);
     attributionSource.readFromParcel(parcel);
-    lpAudioEffect = new AudioEffect(attributionSource);
-    if (lpAudioEffect == 0) {
+    lpAudioEffect = sp<AudioEffect>::make(attributionSource);
+    if (lpAudioEffect == 0) {  // FIXME: I don't think this is actually possible.
         ALOGE("Error creating AudioEffect");
         goto setup_failure;
     }
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index fac32e0..9407122 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -251,15 +251,15 @@
     Mutex::Autolock l(sLock);
     Visualizer* const v =
             (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
-    return sp<Visualizer>(v);
+    return sp<Visualizer>::fromExisting(v);
 }
 
 static sp<Visualizer> setVisualizer(JNIEnv* env, jobject thiz,
                                     const sp<Visualizer>& v)
 {
     Mutex::Autolock l(sLock);
-    sp<Visualizer> old =
-            (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
+    sp<Visualizer> old = sp<Visualizer>::fromExisting(
+            (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer));
     if (v.get()) {
         v->incStrong((void*)setVisualizer);
     }
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index 4f9c6f1..4cccf89 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -19,6 +19,7 @@
 
     static_libs: [
         "androidx.test.core",
+        "androidx.test.ext.truth",
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "mockito-target-minus-junit4",
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index aa486cb..810b408 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -22,6 +22,8 @@
 import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
 import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;
 
+import static androidx.test.ext.truth.os.BundleSubject.assertThat;
+
 import static com.android.mediaroutertest.StubMediaRoute2ProviderService.FEATURE_SAMPLE;
 import static com.android.mediaroutertest.StubMediaRoute2ProviderService.FEATURE_SPECIAL;
 import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID1;
@@ -351,7 +353,7 @@
             }
         }
 
-        assertThat(remoteRouteCount > 0).isTrue();
+        assertThat(remoteRouteCount).isGreaterThan(0);
     }
 
     /**
@@ -384,7 +386,7 @@
 
         mManager.selectRoute(mPackageName, routeToSelect);
         assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
-        assertThat(mManager.getRemoteSessions().size()).isEqualTo(1);
+        assertThat(mManager.getRemoteSessions()).hasSize(1);
     }
 
     @Test
@@ -406,20 +408,20 @@
             }
         });
 
-        assertThat(mManager.getRoutingSessions(mPackageName).size()).isEqualTo(1);
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
 
         mManager.selectRoute(mPackageName, routeToSelect);
         assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
-        assertThat(sessions.size()).isEqualTo(2);
+        assertThat(sessions).hasSize(2);
 
         RoutingSessionInfo sessionInfo = sessions.get(1);
         awaitOnRouteChangedManager(
                 () -> mManager.releaseSession(sessionInfo),
                 ROUTE_ID1,
                 route -> TextUtils.equals(route.getClientPackageName(), null));
-        assertThat(mManager.getRoutingSessions(mPackageName).size()).isEqualTo(1);
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
     }
 
     @Test
@@ -477,20 +479,20 @@
             }
         });
 
-        assertThat(mManager.getRoutingSessions(mPackageName).size()).isEqualTo(1);
-        assertThat(mRouter2.getControllers().size()).isEqualTo(1);
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
+        assertThat(mRouter2.getControllers()).hasSize(1);
 
         mManager.transfer(mManager.getRoutingSessions(mPackageName).get(0), routeToSelect);
         assertThat(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
-        assertThat(mManager.getRoutingSessions(mPackageName).size()).isEqualTo(2);
-        assertThat(mRouter2.getControllers().size()).isEqualTo(2);
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(2);
+        assertThat(mRouter2.getControllers()).hasSize(2);
         mRouter2.getControllers().get(1).release();
 
         assertThat(releaseLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
-        assertThat(mRouter2.getControllers().size()).isEqualTo(1);
-        assertThat(mManager.getRoutingSessions(mPackageName).size()).isEqualTo(1);
+        assertThat(mRouter2.getControllers()).hasSize(1);
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
     }
 
     /**
@@ -596,8 +598,8 @@
                 .map(RoutingSessionInfo::getId)
                 .collect(Collectors.toList());
         // The old session shouldn't appear on the session list.
-        assertThat(remoteSessionIds.contains(sessions.get(0).getId())).isFalse();
-        assertThat(remoteSessionIds.contains(sessions.get(1).getId())).isTrue();
+        assertThat(remoteSessionIds).doesNotContain(sessions.get(0).getId());
+        assertThat(remoteSessionIds).contains(sessions.get(1).getId());
 
         assertThat(serviceOnReleaseSessionLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS))
                 .isFalse();
@@ -705,7 +707,7 @@
         assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
-        assertThat(sessions.size()).isEqualTo(2);
+        assertThat(sessions).hasSize(2);
 
         // test setSessionVolume
         RoutingSessionInfo sessionInfo = sessions.get(1);
@@ -768,7 +770,7 @@
         addManagerCallback(new MediaRouter2Manager.Callback() {});
         mManager.setRouteVolume(volRoute, 0);
         assertThat(onSetRouteVolumeLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
-        assertThat(requestIds.isEmpty()).isFalse();
+        assertThat(requestIds).isNotEmpty();
 
         final int failureReason = REASON_REJECTED;
         final CountDownLatch onRequestFailedLatch = new CountDownLatch(1);
@@ -837,13 +839,13 @@
             @Override
             public void onTransferred(RoutingSessionInfo oldSession,
                     RoutingSessionInfo newSession) {
-                assertThat(newSession.getSelectedRoutes().contains(route.getId())).isTrue();
+                assertThat(newSession.getSelectedRoutes()).contains(route.getId());
                 // The StubMediaRoute2ProviderService is supposed to set control hints
                 // with the given controllerHints.
                 Bundle controlHints = newSession.getControlHints();
                 assertThat(controlHints).isNotNull();
-                assertThat(controlHints.containsKey(TEST_KEY)).isTrue();
-                assertThat(controlHints.getString(TEST_KEY)).isEqualTo(TEST_VALUE);
+                assertThat(controlHints).containsKey(TEST_KEY);
+                assertThat(controlHints).string(TEST_KEY).isEqualTo(TEST_VALUE);
 
                 successLatch.countDown();
             }
@@ -891,11 +893,11 @@
                         .collect(Collectors.toList());
                 for (MediaRoute2Info selectableRoute :
                         mManager.getSelectableRoutes(newSessionInfo)) {
-                    assertThat(selectedRoutes.contains(selectableRoute.getId())).isFalse();
+                    assertThat(selectedRoutes).doesNotContain(selectableRoute.getId());
                 }
                 for (MediaRoute2Info deselectableRoute :
                         mManager.getDeselectableRoutes(newSessionInfo)) {
-                    assertThat(selectedRoutes.contains(deselectableRoute.getId())).isTrue();
+                    assertThat(selectedRoutes).contains(deselectableRoute.getId());
                 }
                 onSessionCreatedLatch.countDown();
             }
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 2e4ef58..edc7d78 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -23,7 +23,7 @@
     <string name="summary_watch" msgid="3002344206574997652">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 프로필을 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, Calendar, 통화 기록, 근처 기기에 대한 권한을 갖게 됩니다."</string>
     <string name="permission_apps" msgid="6142133265286656158">"앱"</string>
     <string name="permission_apps_summary" msgid="798718816711515431">"휴대전화의 앱을 스트리밍합니다."</string>
-    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;이 휴대전화의 이 정보에 액세스하도록 허용합니다."</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 360560a..a632026 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -23,7 +23,7 @@
     <string name="summary_watch" msgid="3002344206574997652">"Ta aplikacja jest niezbędna do zarządzania profilem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i urządzeń w pobliżu."</string>
     <string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string>
     <string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
-    <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
+    <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól urządzeniu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania treści z aplikacji na innym urządzeniu"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 10d46d6..4fb575b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -84,7 +84,7 @@
 public class CompanionDeviceActivity extends FragmentActivity implements
         CompanionVendorHelperDialogFragment.CompanionVendorHelperDialogListener {
     private static final boolean DEBUG = false;
-    private static final String TAG = CompanionDeviceActivity.class.getSimpleName();
+    private static final String TAG = "CDM_CompanionDeviceActivity";
 
     // Keep the following constants in sync with
     // frameworks/base/services/companion/java/
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java
index 93040b5..e13e639c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDataTransferActivity.java
@@ -39,7 +39,7 @@
  */
 public class CompanionDeviceDataTransferActivity extends Activity {
 
-    private static final String LOG_TAG = CompanionDeviceDataTransferActivity.class.getSimpleName();
+    private static final String LOG_TAG = "CDM_CompanionDeviceDataTransferActivity";
 
     // Intent data keys from SystemDataTransferProcessor
     private static final String EXTRA_PERMISSION_SYNC_REQUEST = "permission_sync_request";
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index fc5ff08..732e734 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -70,7 +70,7 @@
  */
 public class CompanionDeviceDiscoveryService extends Service {
     private static final boolean DEBUG = false;
-    private static final String TAG = CompanionDeviceDiscoveryService.class.getSimpleName();
+    private static final String TAG = "CDM_CompanionDeviceDiscoveryService";
 
     private static final String SYS_PROP_DEBUG_TIMEOUT = "debug.cdm.discovery_timeout";
     private static final long TIMEOUT_DEFAULT = 20_000L; // 20 seconds
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
index f2f6cb0..804e7577 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java
@@ -44,7 +44,7 @@
  * A fragmentDialog shows additional information about selfManaged devices
  */
 public class CompanionVendorHelperDialogFragment extends DialogFragment {
-    private static final String TAG = CompanionVendorHelperDialogFragment.class.getSimpleName();
+    private static final String TAG = "CDM_CompanionVendorHelperDialogFragment";
     private static final String ASSOCIATION_REQUEST_EXTRA = "association_request";
 
     private CompanionVendorHelperDialogListener mListener;
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index 55fc5bf..c3291a0 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -35,7 +35,7 @@
     <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"पुर्तगाली"</string>
     <string name="keyboard_layout_slovak" msgid="2469379934672837296">"स्लोवाक"</string>
     <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"स्लोवेनियाई"</string>
-    <string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्की"</string>
+    <string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्किये"</string>
     <string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"Turkish F"</string>
     <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"यूक्रेनियाई"</string>
     <string name="keyboard_layout_arabic" msgid="5671970465174968712">"अरबी"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index 832b855..c1cec38 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -41,7 +41,7 @@
     <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
     <string name="page_description_template" msgid="6831239682256197161">"ገጽ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> ከ<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
     <string name="summary_template" msgid="8899734908625669193">"ማጠቃለያ፣ ቅጂዎች <xliff:g id="COPIES">%1$s</xliff:g>፣ የወረቀት መጠን <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
-    <string name="expand_handle" msgid="7282974448109280522">"እጀታን ወደ ውጪ ላክ"</string>
+    <string name="expand_handle" msgid="7282974448109280522">"እጀታን ወደ ውጭ ላክ"</string>
     <string name="collapse_handle" msgid="6886637989442507451">"እጀታን ሰብስብ"</string>
     <string name="print_button" msgid="645164566271246268">"አትም"</string>
     <string name="savetopdf_button" msgid="2976186791686924743">"ወደ ፔዲኤፍ አስቀምጥ"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 441ae73..90c1937 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -56,6 +56,7 @@
     <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"No recordar impresora"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item>
       <item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item>
     </plurals>
@@ -76,6 +77,7 @@
     <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
     <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Instala para ver <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
       <item quantity="one">Instala para ver <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
     </plurals>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index c1ff282..18e56db 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -56,6 +56,7 @@
     <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Olvidar impresora"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
       <item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
     </plurals>
@@ -76,6 +77,7 @@
     <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
     <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Instalar para descubrir <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
       <item quantity="one">Instalar para descubrir <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
     </plurals>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 3b7775a..082c148 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -57,6 +57,7 @@
     <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
     <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
       <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index f6e901d..560c5dc 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -57,6 +57,7 @@
     <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
     <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
       <item quantity="one">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimante</item>
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Installer pour détecter <xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 96751ea..569bbc2 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -56,6 +56,7 @@
     <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
     </plurals>
@@ -76,6 +77,7 @@
     <string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
     <string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Installa per rilevare <xliff:g id="COUNT_1">%1$s</xliff:g> stampanti</item>
       <item quantity="one">Installa per rilevare <xliff:g id="COUNT_0">%1$s</xliff:g> stampante</item>
     </plurals>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 6ce4636..3b460a1 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -57,6 +57,7 @@
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
     <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
       <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 4517efe..8c1087e 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -56,6 +56,7 @@
     <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
     </plurals>
@@ -76,6 +77,7 @@
     <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
     <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Instale para detetar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
       <item quantity="one">Instale para detetar <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
     </plurals>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 6ce4636..3b460a1 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -57,6 +57,7 @@
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -77,6 +78,7 @@
     <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
     <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
       <item quantity="one">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
+      <item quantity="many">Install to discover <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Instale para encontrar <xliff:g id="COUNT_1">%1$s</xliff:g> impressoras</item>
     </plurals>
     <string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/AppPreference/res/layout/app_header_preference.xml b/packages/SettingsLib/AppPreference/res/layout/app_header_preference.xml
new file mode 100644
index 0000000..a2389a9
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/res/layout/app_header_preference.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="24dp"
+    android:paddingBottom="16dp"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:gravity="center_horizontal"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@android:id/icon"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:scaleType="fitCenter"
+            android:antialias="true"/>
+
+        <TextView
+            android:id="@android:id/title"
+            style="@style/TextAppearance.EntityHeaderTitle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="false"
+            android:gravity="center"
+            android:ellipsize="marquee"
+            android:textDirection="locale"
+            android:layout_marginTop="8dp"/>
+
+        <TextView
+            android:id="@+id/install_type"
+            style="@style/TextAppearance.EntityHeaderSummary"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="2dp"
+            android:text="@string/install_type_instant"/>
+
+        <TextView
+            android:id="@android:id/summary"
+            style="@style/TextAppearance.EntityHeaderSummary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="2dp"
+            android:singleLine="false"
+            android:textAlignment="center"/>
+
+        <TextView
+            android:id="@+id/second_summary"
+            style="@style/TextAppearance.EntityHeaderSummary"
+            android:singleLine="false"
+            android:maxLines="4"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/packages/SettingsLib/AppPreference/res/values/strings.xml b/packages/SettingsLib/AppPreference/res/values/strings.xml
new file mode 100644
index 0000000..ca148c00
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Added as the value of a header field indicating this is an instant app (as opposed to installed normally) -->
+    <string name="install_type_instant">Instant app</string>
+</resources>
diff --git a/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/AppHeaderPreference.java b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/AppHeaderPreference.java
new file mode 100644
index 0000000..60d00da
--- /dev/null
+++ b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/AppHeaderPreference.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * The Preference for the pages need to show big apps icon and name in the header of the page.
+ */
+public class AppHeaderPreference extends Preference {
+
+    private boolean mIsInstantApp;
+    private CharSequence mSecondSummary;
+
+    public AppHeaderPreference(Context context, AttributeSet attrs, int defStyleAttr,
+                               int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    public AppHeaderPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public AppHeaderPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public AppHeaderPreference(Context context) {
+        super(context);
+        init();
+    }
+
+    private void init() {
+        setLayoutResource(R.layout.app_header_preference);
+        setSelectable(false);
+        setIsInstantApp(false);
+    }
+
+    /**
+     * Returns the installation type of this preference.
+     *
+     * @return whether the app is an instant app
+     * @see #setIsInstantApp(boolean)
+     */
+    public boolean getIsInstantApp() {
+        return mIsInstantApp;
+    }
+
+    /**
+     * Sets the installation type for this preference with a boolean.
+     *
+     * @param isInstantApp whether the app is an instant app
+     */
+    public void setIsInstantApp(@NonNull boolean isInstantApp) {
+        if (mIsInstantApp != isInstantApp) {
+            mIsInstantApp = isInstantApp;
+            notifyChanged();
+        }
+    }
+
+    /**
+     * Returns the second summary of this preference.
+     *
+     * @return The second summary
+     * @see #setSecondSummary(CharSequence)
+     */
+    @Nullable
+    public CharSequence getSecondSummary() {
+        return mSecondSummary;
+    }
+
+    /**
+     * Sets the second summary for this preference with a CharSequence.
+     *
+     * @param secondSummary The second summary for the preference
+     */
+    public void setSecondSummary(@Nullable CharSequence secondSummary) {
+        if (!TextUtils.equals(mSecondSummary, secondSummary)) {
+            mSecondSummary = secondSummary;
+            notifyChanged();
+        }
+    }
+
+    /**
+     * Sets the second summary for this preference with a resource ID.
+     *
+     * @param secondSummaryResId The second summary as a resource
+     * @see #setSecondSummary(CharSequence)
+     */
+    public void setSecondSummary(@StringRes int secondSummaryResId) {
+        setSecondSummary(getContext().getString(secondSummaryResId));
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+
+        final TextView installTypeView = (TextView) holder.findViewById(R.id.install_type);
+        if (installTypeView != null) {
+            if (mIsInstantApp) {
+                installTypeView.setVisibility(View.VISIBLE);
+            } else {
+                installTypeView.setVisibility(View.GONE);
+            }
+        }
+
+        final TextView secondSummaryView = (TextView) holder.findViewById(R.id.second_summary);
+        if (secondSummaryView != null) {
+            if (!TextUtils.isEmpty(mSecondSummary)) {
+                secondSummaryView.setText(mSecondSummary);
+                secondSummaryView.setVisibility(View.VISIBLE);
+            } else {
+                secondSummaryView.setVisibility(View.GONE);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 7968e96..50f8e54 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -28,5 +28,6 @@
         "com.android.adservices",
         "com.android.cellbroadcast",
         "com.android.permission",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
index ead5174..0de7be0 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
@@ -43,6 +43,8 @@
     <color name="settingslib_color_grey400">#bdc1c6</color>
     <color name="settingslib_color_grey300">#dadce0</color>
     <color name="settingslib_color_grey200">#e8eaed</color>
+    <color name="settingslib_color_grey100">#f1f3f4</color>
+    <color name="settingslib_color_grey50">#f8f9fa</color>
     <color name="settingslib_color_orange600">#e8710a</color>
     <color name="settingslib_color_orange400">#fa903e</color>
     <color name="settingslib_color_orange300">#fcad70</color>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
new file mode 100644
index 0000000..93b6acc
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.airbnb.lottie.LottieProperty;
+import com.airbnb.lottie.model.KeyPath;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Util class which dynamically changes the color of tags in a lottie json file between Dark Theme
+ * (DT) and Light Theme (LT). This class assumes the json file is for Dark Theme.
+ */
+public class LottieColorUtils {
+    private static final Map<String, Integer> DARK_TO_LIGHT_THEME_COLOR_MAP;
+
+    static {
+        HashMap<String, Integer> map = new HashMap<>();
+        map.put(
+                ".grey600",
+                R.color.settingslib_color_grey300);
+        map.put(
+                ".grey800",
+                R.color.settingslib_color_grey200);
+        map.put(
+                ".grey900",
+                R.color.settingslib_color_grey50);
+        map.put(
+                ".red400",
+                R.color.settingslib_color_red600);
+        map.put(
+                ".black",
+                android.R.color.white);
+        map.put(
+                ".blue400",
+                R.color.settingslib_color_blue600);
+        map.put(
+                ".green400",
+                R.color.settingslib_color_green600);
+        DARK_TO_LIGHT_THEME_COLOR_MAP = Collections.unmodifiableMap(map);
+    }
+
+    private LottieColorUtils() {
+    }
+
+    private static boolean isDarkMode(Context context) {
+        return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+    }
+
+    /** Applies dynamic colors based on DT vs. LT. The LottieAnimationView should be Dark Theme. */
+    public static void applyDynamicColors(Context context,
+            LottieAnimationView lottieAnimationView) {
+        // Assume the default for the lottie is dark mode
+        if (isDarkMode(context)) {
+            return;
+        }
+        for (String key : DARK_TO_LIGHT_THEME_COLOR_MAP.keySet()) {
+            final int color = context.getColor(DARK_TO_LIGHT_THEME_COLOR_MAP.get(key));
+            lottieAnimationView.addValueCallback(
+                    new KeyPath("**", key, "**"),
+                    LottieProperty.COLOR_FILTER,
+                    frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+        }
+    }
+}
diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/LayoutPreference/Android.bp
index aaffdc9..c29e1f7 100644
--- a/packages/SettingsLib/LayoutPreference/Android.bp
+++ b/packages/SettingsLib/LayoutPreference/Android.bp
@@ -15,6 +15,7 @@
 
     static_libs: [
         "androidx.preference_preference",
+        "SettingsLibSettingsTheme",
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
index 2bdd6fe..f958037 100644
--- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml
+++ b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
@@ -22,20 +22,6 @@
         <item name="android:paddingEnd">16dp</item>
     </style>
 
-    <style name="TextAppearance.EntityHeaderTitle"
-           parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:textSize">20sp</item>
-    </style>
-
-    <style name="TextAppearance.EntityHeaderSummary"
-           parent="@android:style/TextAppearance.DeviceDefault">
-        <item name="android:textAlignment">viewStart</item>
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:ellipsize">marquee</item>
-    </style>
-
     <style name="CrossProfileEntityHeaderIcon">
         <item name="android:layout_width">48dp</item>
         <item name="android:layout_height">48dp</item>
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 1f69c85..82e0220 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -23,5 +23,6 @@
         "com.android.cellbroadcast",
         "com.android.permission",
         "com.android.adservices",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles.xml b/packages/SettingsLib/SettingsTheme/res/values/styles.xml
index 00bd141..328ab46 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles.xml
@@ -33,4 +33,18 @@
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
+    <style name="TextAppearance.EntityHeaderTitle"
+        parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">20sp</item>
+    </style>
+
+    <style name="TextAppearance.EntityHeaderSummary"
+        parent="@android:style/TextAppearance.DeviceDefault">
+        <item name="android:textAlignment">viewStart</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:ellipsize">marquee</item>
+    </style>
+
 </resources>
diff --git a/packages/SettingsLib/SettingsTransition/Android.bp b/packages/SettingsLib/SettingsTransition/Android.bp
index 708141b..be77845 100644
--- a/packages/SettingsLib/SettingsTransition/Android.bp
+++ b/packages/SettingsLib/SettingsTransition/Android.bp
@@ -23,5 +23,6 @@
         "com.android.adservices",
         "com.android.cellbroadcast",
         "com.android.permission",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
index 2229986..e583138 100644
--- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
+++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
@@ -20,7 +20,8 @@
     <application
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_label"
-        android:supportsRtl="true">
+        android:supportsRtl="true"
+        android:enableOnBackInvokedCallback="true">
         <activity
             android:name=".MainActivity"
             android:exported="true">
@@ -29,6 +30,18 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-    </application>
 
+        <activity
+            android:name=".GalleryDebugActivity"
+            android:exported="true">
+        </activity>
+
+        <provider
+            android:name=".GalleryEntryProvider"
+            android:authorities="com.android.spa.gallery.provider"
+            android:enabled="true"
+            android:exported="false">
+        </provider>
+
+    </application>
 </manifest>
diff --git a/packages/SettingsLib/Spa/gallery/res/raw/accessibility_shortcut_type_triple_tap.json b/packages/SettingsLib/Spa/gallery/res/raw/accessibility_shortcut_type_triple_tap.json
new file mode 100644
index 0000000..870e671
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/res/raw/accessibility_shortcut_type_triple_tap.json
@@ -0,0 +1,1959 @@
+{
+  "v": "5.6.5",
+  "fr": 60,
+  "ip": 0,
+  "op": 180,
+  "w": 412,
+  "h": 300,
+  "nm": "Triple_Tap_Screen",
+  "ddd": 0,
+  "assets": [
+    {
+      "id": "comp_0",
+      "layers": [
+        {
+          "ddd": 0,
+          "ind": 1,
+          "ty": 4,
+          "nm": ".white",
+          "cl": "white",
+          "hd": true,
+          "sr": 1,
+          "ks": {
+            "o": {
+              "a": 0,
+              "k": 100,
+              "ix": 11
+            },
+            "r": {
+              "a": 0,
+              "k": 0,
+              "ix": 10
+            },
+            "p": {
+              "a": 0,
+              "k": [
+                206,
+                150,
+                0
+              ],
+              "ix": 2
+            },
+            "a": {
+              "a": 0,
+              "k": [
+                0,
+                0,
+                0
+              ],
+              "ix": 1
+            },
+            "s": {
+              "a": 0,
+              "k": [
+                100,
+                100,
+                100
+              ],
+              "ix": 6
+            }
+          },
+          "ao": 0,
+          "shapes": [
+            {
+              "ty": "gr",
+              "it": [
+                {
+                  "ind": 0,
+                  "ty": "sh",
+                  "ix": 1,
+                  "ks": {
+                    "a": 0,
+                    "k": {
+                      "i": [
+                        [
+                          15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          15.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          -15.4
+                        ],
+                        [
+                          0,
+                          0
+                        ]
+                      ],
+                      "o": [
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          -15.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          15.4
+                        ]
+                      ],
+                      "v": [
+                        [
+                          178,
+                          150
+                        ],
+                        [
+                          -178,
+                          150
+                        ],
+                        [
+                          -206,
+                          122
+                        ],
+                        [
+                          -206,
+                          -122
+                        ],
+                        [
+                          -178,
+                          -150
+                        ],
+                        [
+                          178,
+                          -150
+                        ],
+                        [
+                          206,
+                          -122
+                        ],
+                        [
+                          206,
+                          122
+                        ]
+                      ],
+                      "c": true
+                    },
+                    "ix": 2
+                  },
+                  "nm": "Path 1",
+                  "mn": "ADBE Vector Shape - Group",
+                  "hd": false
+                },
+                {
+                  "ty": "fl",
+                  "c": {
+                    "a": 0,
+                    "k": [
+                      1,
+                      1,
+                      1,
+                      1
+                    ],
+                    "ix": 4
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 5
+                  },
+                  "r": 1,
+                  "bm": 0,
+                  "nm": "Fill 1",
+                  "mn": "ADBE Vector Graphic - Fill",
+                  "hd": false
+                },
+                {
+                  "ty": "tr",
+                  "p": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 2
+                  },
+                  "a": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 1
+                  },
+                  "s": {
+                    "a": 0,
+                    "k": [
+                      100,
+                      100
+                    ],
+                    "ix": 3
+                  },
+                  "r": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 6
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 7
+                  },
+                  "sk": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 4
+                  },
+                  "sa": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 5
+                  },
+                  "nm": "Transform"
+                }
+              ],
+              "nm": "Group 1",
+              "np": 2,
+              "cix": 2,
+              "bm": 0,
+              "ix": 1,
+              "mn": "ADBE Vector Group",
+              "hd": false
+            }
+          ],
+          "ip": 0,
+          "op": 1800,
+          "st": 0,
+          "bm": 0
+        }
+      ]
+    }
+  ],
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 1,
+      "ty": 4,
+      "nm": ".grey200",
+      "cl": "grey200",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            206,
+            150,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            1.35,
+            0,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "ind": 0,
+              "ty": "sh",
+              "ix": 1,
+              "ks": {
+                "a": 0,
+                "k": {
+                  "i": [
+                    [
+                      0,
+                      0
+                    ],
+                    [
+                      0,
+                      -73.4
+                    ],
+                    [
+                      -73.4,
+                      0
+                    ],
+                    [
+                      0,
+                      73.4
+                    ],
+                    [
+                      73.4,
+                      0
+                    ]
+                  ],
+                  "o": [
+                    [
+                      -73.4,
+                      0
+                    ],
+                    [
+                      0,
+                      73.4
+                    ],
+                    [
+                      73.4,
+                      0
+                    ],
+                    [
+                      0,
+                      -73.4
+                    ],
+                    [
+                      0,
+                      0
+                    ]
+                  ],
+                  "v": [
+                    [
+                      1.4,
+                      -132.9
+                    ],
+                    [
+                      -131.6,
+                      0
+                    ],
+                    [
+                      1.3,
+                      132.9
+                    ],
+                    [
+                      134.3,
+                      0
+                    ],
+                    [
+                      1.4,
+                      -132.9
+                    ]
+                  ],
+                  "c": true
+                },
+                "ix": 2
+              },
+              "nm": "Path 1",
+              "mn": "ADBE Vector Shape - Group",
+              "hd": false
+            },
+            {
+              "ind": 1,
+              "ty": "sh",
+              "ix": 2,
+              "ks": {
+                "a": 0,
+                "k": {
+                  "i": [
+                    [
+                      0,
+                      0
+                    ],
+                    [
+                      -24.7,
+                      -24.8
+                    ],
+                    [
+                      0,
+                      -35
+                    ],
+                    [
+                      24.8,
+                      -24.7
+                    ],
+                    [
+                      35,
+                      0
+                    ],
+                    [
+                      24.7,
+                      24.8
+                    ],
+                    [
+                      0,
+                      35
+                    ],
+                    [
+                      -24.8,
+                      24.7
+                    ],
+                    [
+                      -35,
+                      0
+                    ]
+                  ],
+                  "o": [
+                    [
+                      35,
+                      0
+                    ],
+                    [
+                      24.7,
+                      24.7
+                    ],
+                    [
+                      0,
+                      35
+                    ],
+                    [
+                      -24.7,
+                      24.7
+                    ],
+                    [
+                      -35,
+                      0
+                    ],
+                    [
+                      -24.7,
+                      -24.8
+                    ],
+                    [
+                      0,
+                      -35
+                    ],
+                    [
+                      24.7,
+                      -24.7
+                    ],
+                    [
+                      0,
+                      0
+                    ]
+                  ],
+                  "v": [
+                    [
+                      1.4,
+                      -130.9
+                    ],
+                    [
+                      94,
+                      -92.5
+                    ],
+                    [
+                      132.4,
+                      0.1
+                    ],
+                    [
+                      94,
+                      92.7
+                    ],
+                    [
+                      1.4,
+                      131.1
+                    ],
+                    [
+                      -91.2,
+                      92.7
+                    ],
+                    [
+                      -129.6,
+                      0
+                    ],
+                    [
+                      -91.2,
+                      -92.6
+                    ],
+                    [
+                      1.4,
+                      -130.9
+                    ]
+                  ],
+                  "c": false
+                },
+                "ix": 2
+              },
+              "nm": "Path 2",
+              "mn": "ADBE Vector Shape - Group",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  0.909803926945,
+                  0.917647063732,
+                  0.929411768913,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Group 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 0,
+      "op": 300,
+      "st": 0,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 2,
+      "ty": 4,
+      "nm": ".grey300",
+      "cl": "grey300",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            205,
+            150,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            0,
+            0,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "ty": "gr",
+              "it": [
+                {
+                  "ind": 0,
+                  "ty": "sh",
+                  "ix": 1,
+                  "ks": {
+                    "a": 0,
+                    "k": {
+                      "i": [
+                        [
+                          -7.9,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          8
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          1.6
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          2,
+                          1.5
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          6.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          6.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          1,
+                          -0.7
+                        ],
+                        [
+                          0,
+                          0
+                        ]
+                      ],
+                      "o": [
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          8,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          1.6,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -1.9,
+                          -1.6
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          6.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -6.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -1,
+                          0.7
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0.1,
+                          7.9
+                        ]
+                      ],
+                      "v": [
+                        [
+                          -64,
+                          75.3
+                        ],
+                        [
+                          69.1,
+                          75.3
+                        ],
+                        [
+                          83.6,
+                          60.8
+                        ],
+                        [
+                          83.6,
+                          -81
+                        ],
+                        [
+                          86.5,
+                          -83.9
+                        ],
+                        [
+                          86.5,
+                          -100.9
+                        ],
+                        [
+                          80.7,
+                          -105.6
+                        ],
+                        [
+                          80.7,
+                          60.8
+                        ],
+                        [
+                          69.1,
+                          72.4
+                        ],
+                        [
+                          -64,
+                          72.4
+                        ],
+                        [
+                          -75.6,
+                          60.8
+                        ],
+                        [
+                          -75.6,
+                          -107.3
+                        ],
+                        [
+                          -78.5,
+                          -105.2
+                        ],
+                        [
+                          -78.5,
+                          60.9
+                        ]
+                      ],
+                      "c": true
+                    },
+                    "ix": 2
+                  },
+                  "nm": "Path 1",
+                  "mn": "ADBE Vector Shape - Group",
+                  "hd": false
+                },
+                {
+                  "ty": "fl",
+                  "c": {
+                    "a": 0,
+                    "k": [
+                      0.854901969433,
+                      0.86274510622,
+                      0.878431379795,
+                      1
+                    ],
+                    "ix": 4
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 5
+                  },
+                  "r": 1,
+                  "bm": 0,
+                  "nm": "Fill 1",
+                  "mn": "ADBE Vector Graphic - Fill",
+                  "hd": false
+                },
+                {
+                  "ty": "tr",
+                  "p": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 2
+                  },
+                  "a": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 1
+                  },
+                  "s": {
+                    "a": 0,
+                    "k": [
+                      100,
+                      100
+                    ],
+                    "ix": 3
+                  },
+                  "r": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 6
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 7
+                  },
+                  "sk": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 4
+                  },
+                  "sa": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 5
+                  },
+                  "nm": "Transform"
+                }
+              ],
+              "nm": "Group 1",
+              "np": 2,
+              "cix": 2,
+              "bm": 0,
+              "ix": 1,
+              "mn": "ADBE Vector Group",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Group 1",
+          "np": 1,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 0,
+      "op": 300,
+      "st": 0,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 3,
+      "ty": 4,
+      "nm": "cursor 5",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 36,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 39.582,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 44.953,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 55.697265625,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            207.641,
+            154.48,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -180.5,
+            -165.5,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0,
+                  0,
+                  0
+                ],
+                "y": [
+                  1,
+                  1,
+                  1
+                ]
+              },
+              "o": {
+                "x": [
+                  0.45,
+                  0.45,
+                  0.45
+                ],
+                "y": [
+                  0,
+                  0,
+                  0
+                ]
+              },
+              "t": 37.791,
+              "s": [
+                27.252,
+                27.252,
+                100
+              ]
+            },
+            {
+              "t": 59,
+              "s": [
+                56.661,
+                56.661,
+                100
+              ]
+            }
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "d": 1,
+              "ty": "el",
+              "s": {
+                "a": 0,
+                "k": [
+                  63.109,
+                  63.109
+                ],
+                "ix": 2
+              },
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 3
+              },
+              "nm": "Ellipse Path 1",
+              "mn": "ADBE Vector Shape - Ellipse",
+              "hd": false
+            },
+            {
+              "ty": "st",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.182245725744,
+                  0.894323072246,
+                  1
+                ],
+                "ix": 3
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "w": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "lc": 1,
+              "lj": 1,
+              "ml": 4,
+              "bm": 0,
+              "nm": "Stroke 1",
+              "mn": "ADBE Vector Graphic - Stroke",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.522196631338,
+                  0.9762855081,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 50,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  -180.5,
+                  -165.5
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Ellipse 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 36,
+      "op": 59,
+      "st": -1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 4,
+      "ty": 4,
+      "nm": "cursor 4",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 22,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 25.58,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 30.953,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 41.697265625,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            207.641,
+            154.48,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -180.5,
+            -165.5,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0,
+                  0,
+                  0
+                ],
+                "y": [
+                  1,
+                  1,
+                  1
+                ]
+              },
+              "o": {
+                "x": [
+                  0.45,
+                  0.45,
+                  0.45
+                ],
+                "y": [
+                  0,
+                  0,
+                  0
+                ]
+              },
+              "t": 23.789,
+              "s": [
+                27.252,
+                27.252,
+                100
+              ]
+            },
+            {
+              "t": 45,
+              "s": [
+                56.661,
+                56.661,
+                100
+              ]
+            }
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "d": 1,
+              "ty": "el",
+              "s": {
+                "a": 0,
+                "k": [
+                  63.109,
+                  63.109
+                ],
+                "ix": 2
+              },
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 3
+              },
+              "nm": "Ellipse Path 1",
+              "mn": "ADBE Vector Shape - Ellipse",
+              "hd": false
+            },
+            {
+              "ty": "st",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.182245725744,
+                  0.894323072246,
+                  1
+                ],
+                "ix": 3
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "w": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "lc": 1,
+              "lj": 1,
+              "ml": 4,
+              "bm": 0,
+              "nm": "Stroke 1",
+              "mn": "ADBE Vector Graphic - Stroke",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.522196631338,
+                  0.9762855081,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 50,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  -180.5,
+                  -165.5
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Ellipse 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 22,
+      "op": 45,
+      "st": -3,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 5,
+      "ty": 4,
+      "nm": "cursor",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 8,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 11.582,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 16.953,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 27.697265625,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            207.641,
+            154.48,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -180.5,
+            -165.5,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0,
+                  0,
+                  0
+                ],
+                "y": [
+                  1,
+                  1,
+                  1
+                ]
+              },
+              "o": {
+                "x": [
+                  0.45,
+                  0.45,
+                  0.45
+                ],
+                "y": [
+                  0,
+                  0,
+                  0
+                ]
+              },
+              "t": 9.791,
+              "s": [
+                27.252,
+                27.252,
+                100
+              ]
+            },
+            {
+              "t": 31,
+              "s": [
+                56.661,
+                56.661,
+                100
+              ]
+            }
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "d": 1,
+              "ty": "el",
+              "s": {
+                "a": 0,
+                "k": [
+                  63.109,
+                  63.109
+                ],
+                "ix": 2
+              },
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 3
+              },
+              "nm": "Ellipse Path 1",
+              "mn": "ADBE Vector Shape - Ellipse",
+              "hd": false
+            },
+            {
+              "ty": "st",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.182245725744,
+                  0.894323072246,
+                  1
+                ],
+                "ix": 3
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "w": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "lc": 1,
+              "lj": 1,
+              "ml": 4,
+              "bm": 0,
+              "nm": "Stroke 1",
+              "mn": "ADBE Vector Graphic - Stroke",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.522196631338,
+                  0.9762855081,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 50,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  -180.5,
+                  -165.5
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Ellipse 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 8,
+      "op": 31,
+      "st": -5,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 6,
+      "ty": 0,
+      "nm": "BG_White",
+      "refId": "comp_0",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            206,
+            150,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            206,
+            150,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "w": 412,
+      "h": 300,
+      "ip": 0,
+      "op": 1800,
+      "st": 0,
+      "bm": 0
+    }
+  ],
+  "markers": []
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt
index 1de740a..317346d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.settingslib.spa.gallery
 
-import android.annotation.UserIdInt;
-import android.content.Context;
+import com.android.settingslib.spa.framework.DebugActivity
 
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+class GalleryDebugActivity : DebugActivity(SpaEnvironment.EntryRepository, MainActivity::class.java)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryEntryProvider.kt
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryEntryProvider.kt
index 1de740a..3210eb5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryEntryProvider.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.settingslib.spa.gallery
 
-import android.annotation.UserIdInt;
-import android.content.Context;
+import com.android.settingslib.spa.framework.EntryProvider
 
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
-}
+class GalleryEntryProvider : EntryProvider(
+    SpaEnvironment.EntryRepository,
+    "com.android.settingslib.spa.gallery/.MainActivity",
+)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
index e75e76c..787d096 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt
@@ -51,8 +51,8 @@
                 IllustrationPageProvider,
             ),
             rootPages = listOf(
-                SettingsPage(HomePageProvider.name)
-            ) + ArgumentPageProvider.buildRootPages()
+                SettingsPage.create(HomePageProvider.name)
+            )
         )
     }
 
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
index 2428bba..d8ef937 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
@@ -17,15 +17,15 @@
 package com.android.settingslib.spa.gallery.home
 
 import android.os.Bundle
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.gallery.R
-import com.android.settingslib.spa.gallery.SpaEnvironment
+import com.android.settingslib.spa.gallery.page.ArgumentPageModel
 import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
 import com.android.settingslib.spa.gallery.page.FooterPageProvider
 import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
@@ -38,33 +38,29 @@
 object HomePageProvider : SettingsPageProvider {
     override val name = "Home"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        return listOf(
+            PreferenceMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            ArgumentPageProvider.buildInjectEntry("foo")!!.setLink(fromPage = owner).build(),
+            SliderPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            SpinnerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            SettingsPagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            FooterPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            IllustrationPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+        )
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        HomePage()
-    }
-}
-
-@Composable
-private fun HomePage() {
-    HomeScaffold(title = stringResource(R.string.app_name)) {
-        PreferenceMainPageProvider.EntryItem()
-        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)
-
-        SliderPageProvider.EntryItem()
-        SpinnerPageProvider.EntryItem()
-        SettingsPagerPageProvider.EntryItem()
-        FooterPageProvider.EntryItem()
-        IllustrationPageProvider.EntryItem()
-
-        /**
-         * A test button to generate hierarchy.
-         * TODO: remove it once the content provider is ready.
-         */
-        Button(onClick = {
-            SpaEnvironment.EntryRepository.printAllPages()
-            SpaEnvironment.EntryRepository.printAllEntries()
-        }) {
-            Text(text = "Generate Entry")
+        HomeScaffold(title = stringResource(R.string.app_name)) {
+            for (entry in buildEntry(arguments)) {
+                if (entry.name.startsWith(ArgumentPageModel.name)) {
+                    entry.UiLayout(ArgumentPageModel.buildArgument(intParam = 0))
+                } else {
+                    entry.UiLayout()
+                }
+            }
         }
     }
 }
@@ -73,6 +69,6 @@
 @Composable
 private fun HomeScreenPreview() {
     SettingsTheme {
-        HomePage()
+        HomePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index 5fe17e5..e32de7a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -43,7 +43,7 @@
                 .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     // Set ui rendering
-                    Preference(ArgumentPageModel.create(arguments).genStringParamPreferenceModel())
+                    Preference(ArgumentPageModel.create(it).genStringParamPreferenceModel())
                 }.build()
         )
 
@@ -53,51 +53,44 @@
                 .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     // Set ui rendering
-                    Preference(ArgumentPageModel.create(arguments).genIntParamPreferenceModel())
+                    Preference(ArgumentPageModel.create(it).genIntParamPreferenceModel())
                 }.build()
         )
 
-        val entryFoo = buildInjectEntry(ArgumentPageModel.buildNextArgument("foo", arguments))
-        val entryBar = buildInjectEntry(ArgumentPageModel.buildNextArgument("bar", arguments))
-        if (entryFoo != null) entryList.add(entryFoo.setLink(fromPage = owner).build())
-        if (entryBar != null) entryList.add(entryBar.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("foo")!!.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("bar")!!.setLink(fromPage = owner).build())
 
         return entryList
     }
 
-    private fun buildInjectEntry(arguments: Bundle?): SettingsEntryBuilder? {
+    fun buildInjectEntry(stringParam: String): SettingsEntryBuilder? {
+        val arguments = ArgumentPageModel.buildArgument(stringParam)
         if (!ArgumentPageModel.isValidArgument(arguments)) return null
 
-        return SettingsEntryBuilder.createInject(SettingsPage.create(name, parameter, arguments))
+        return SettingsEntryBuilder.createInject(
+            entryName = "${name}_$stringParam",
+            owner = SettingsPage.create(name, parameter, arguments)
+        )
             // Set attributes
             .setIsAllowSearch(false)
             .setUiLayoutFn {
                 // Set ui rendering
-                Preference(ArgumentPageModel.create(arguments).genInjectPreferenceModel())
+                Preference(ArgumentPageModel.create(it).genInjectPreferenceModel())
             }
     }
 
-    fun buildRootPages(): List<SettingsPage> {
-        return listOf(
-            SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("foo")),
-            SettingsPage.create(name, parameter, ArgumentPageModel.buildArgument("bar")),
-        )
-    }
-
     @Composable
     override fun Page(arguments: Bundle?) {
         RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
             for (entry in buildEntry(arguments)) {
-                entry.uiLayout()
+                if (entry.name.startsWith(name)) {
+                    entry.UiLayout(ArgumentPageModel.buildNextArgument(arguments))
+                } else {
+                    entry.UiLayout()
+                }
             }
         }
     }
-
-    @Composable
-    fun EntryItem(stringParam: String, intParam: Int) {
-        buildInjectEntry(ArgumentPageModel.buildArgument(stringParam, intParam))
-            ?.build()?.uiLayout?.let { it() }
-    }
 }
 
 @Preview(showBackground = true)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
index 8b94342..6e86fd7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
@@ -22,6 +22,7 @@
 import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
+import com.android.settingslib.spa.framework.BrowseActivity
 import com.android.settingslib.spa.framework.common.PageModel
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -43,19 +44,17 @@
             navArgument(INT_PARAM_NAME) { type = NavType.IntType },
         )
 
-        fun buildArgument(stringParam: String, intParam: Int? = null): Bundle {
+        fun buildArgument(stringParam: String? = null, intParam: Int? = null): Bundle {
             val args = Bundle()
-            args.putString(STRING_PARAM_NAME, stringParam)
+            if (stringParam != null) args.putString(STRING_PARAM_NAME, stringParam)
             if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
             return args
         }
 
-        fun buildNextArgument(newStringParam: String, arguments: Bundle? = null): Bundle {
+        fun buildNextArgument(arguments: Bundle? = null): Bundle {
             val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
-            return if (intParam == null)
-                buildArgument(newStringParam)
-            else
-                buildArgument(newStringParam, intParam + 1)
+            val nextIntParam = if (intParam != null) intParam + 1 else null
+            return buildArgument(intParam = nextIntParam)
         }
 
         fun isValidArgument(arguments: Bundle?): Boolean {
@@ -75,12 +74,14 @@
     private var arguments: Bundle? = null
     private var stringParam: String? = null
     private var intParam: Int? = null
+    private var highlightName: String? = null
 
     override fun initialize(arguments: Bundle?) {
         logMsg("init with args " + arguments.toString())
         this.arguments = arguments
         stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
         intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
+        highlightName = arguments?.getString(BrowseActivity.HIGHLIGHT_ENTRY_PARAM_NAME)
     }
 
     @Composable
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
index 4a933ac..0fc2a5f 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
@@ -20,6 +20,9 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -34,30 +37,44 @@
 object FooterPageProvider : SettingsPageProvider {
     override val name = "Footer"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "Some Preference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(remember {
+                        object : PreferenceModel {
+                            override val title = "Some Preference"
+                            override val summary = stateOf("Some summary")
+                        }
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        FooterPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun FooterPage() {
-    RegularScaffold(title = TITLE) {
-        Preference(remember {
-            object : PreferenceModel {
-                override val title = "Some Preference"
-                override val summary = stateOf("Some summary")
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
             }
-        })
-        Footer(footerText = "Footer text always at the end of page.")
+            Footer(footerText = "Footer text always at the end of page.")
+        }
     }
 }
 
@@ -65,6 +82,6 @@
 @Composable
 private fun FooterPagePreview() {
     SettingsTheme {
-        FooterPage()
+        FooterPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
index 5db6e7a..a64d4a5 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
@@ -17,12 +17,11 @@
 package com.android.settingslib.spa.gallery.page
 
 import android.os.Bundle
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -32,35 +31,64 @@
 import com.android.settingslib.spa.widget.ResourceType
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+
+private const val TITLE = "Sample Illustration"
 
 object IllustrationPageProvider : SettingsPageProvider {
     override val name = "Illustration"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "Lottie Illustration", owner)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Lottie Illustration"
+                    })
+
+                    Illustration(object : IllustrationModel {
+                        override val resId = R.raw.accessibility_shortcut_type_triple_tap
+                        override val resourceType = ResourceType.LOTTIE
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "Image Illustration", owner)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Image Illustration"
+                    })
+
+                    Illustration(object : IllustrationModel {
+                        override val resId = R.drawable.accessibility_captioning_banner
+                        override val resourceType = ResourceType.IMAGE
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+     fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        IllustrationPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = "Sample Illustration"
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun IllustrationPage() {
-    Column(Modifier.verticalScroll(rememberScrollState())) {
-        Preference(object : PreferenceModel {
-            override val title = "Image Illustration"
-        })
-
-        Illustration(object : IllustrationModel {
-            override val resId = R.drawable.accessibility_captioning_banner
-            override val resourceType = ResourceType.IMAGE
-        })
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -68,6 +96,6 @@
 @Composable
 private fun IllustrationPagePreview() {
     SettingsTheme {
-        IllustrationPage()
+        IllustrationPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
index 9d80818..e09ebda 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
@@ -19,6 +19,8 @@
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -33,25 +35,23 @@
 object SettingsPagerPageProvider : SettingsPageProvider {
     override val name = "SettingsPager"
 
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SettingsPagerPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SettingsPagerPage() {
-    SettingsScaffold(title = TITLE) {
-        SettingsPager(listOf("Personal", "Work")) {
-            PlaceholderTitle("Page $it")
+        SettingsScaffold(title = TITLE) {
+            SettingsPager(listOf("Personal", "Work")) {
+                PlaceholderTitle("Page $it")
+            }
         }
     }
 }
@@ -60,6 +60,6 @@
 @Composable
 private fun SettingsPagerPagePreview() {
     SettingsTheme {
-        SettingsPagerPage()
+        SettingsPagerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
index 130cbd9..0f95bf6 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
@@ -27,6 +27,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -41,59 +44,88 @@
 object SliderPageProvider : SettingsPageProvider {
     override val name = "Slider"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create("Simple Slider", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Simple Slider"
+                        override val initValue = 40
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Slider with icon", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Slider with icon"
+                        override val initValue = 30
+                        override val onValueChangeFinished = {
+                            println("onValueChangeFinished")
+                        }
+                        override val icon = Icons.Outlined.AccessAlarm
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Slider with changeable icon", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    val initValue = 0
+                    var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) }
+                    var sliderPosition by remember { mutableStateOf(initValue) }
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Slider with changeable icon"
+                        override val initValue = initValue
+                        override val onValueChange = { it: Int ->
+                            sliderPosition = it
+                            icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff
+                        }
+                        override val onValueChangeFinished = {
+                            println("onValueChangeFinished: the value is $sliderPosition")
+                        }
+                        override val icon = icon
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Slider with steps", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SettingsSlider(object : SettingsSliderModel {
+                        override val title = "Slider with steps"
+                        override val initValue = 2
+                        override val valueRange = 1..5
+                        override val showSteps = true
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SliderPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SliderPage() {
-    RegularScaffold(title = TITLE) {
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider"
-            override val initValue = 40
-        })
-
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider with icon"
-            override val initValue = 30
-            override val onValueChangeFinished = {
-                println("onValueChangeFinished")
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
             }
-            override val icon = Icons.Outlined.AccessAlarm
-        })
-
-        val initValue = 0
-        var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) }
-        var sliderPosition by remember { mutableStateOf(initValue) }
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider with changeable icon"
-            override val initValue = initValue
-            override val onValueChange = { it: Int ->
-                sliderPosition = it
-                icon = if (it > 0) Icons.Outlined.MusicNote else Icons.Outlined.MusicOff
-            }
-            override val onValueChangeFinished = {
-                println("onValueChangeFinished: the value is $sliderPosition")
-            }
-            override val icon = icon
-        })
-
-        SettingsSlider(object : SettingsSliderModel {
-            override val title = "Slider with steps"
-            override val initValue = 2
-            override val valueRange = 1..5
-            override val showSteps = true
-        })
+        }
     }
 }
 
@@ -101,6 +133,6 @@
 @Composable
 private fun SliderPagePreview() {
     SettingsTheme {
-        SliderPage()
+        SliderPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
index 53d7648..a8e4938 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
@@ -22,6 +22,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -37,25 +40,45 @@
 object MainSwitchPreferencePageProvider : SettingsPageProvider {
     override val name = "MainSwitchPreference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "MainSwitchPreference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleMainSwitchPreference()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "MainSwitchPreference not changeable", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleNotChangeableMainSwitchPreference()
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        MainSwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun MainSwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        SampleMainSwitchPreference()
-        SampleNotChangeableMainSwitchPreference()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -88,6 +111,6 @@
 @Composable
 private fun MainSwitchPreferencePagePreview() {
     SettingsTheme {
-        MainSwitchPreferencePage()
+        MainSwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
index 0a8dae3..0f99c57 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
@@ -18,6 +18,9 @@
 
 import android.os.Bundle
 import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.widget.preference.Preference
@@ -29,26 +32,36 @@
 object PreferenceMainPageProvider : SettingsPageProvider {
     override val name = "PreferenceMain"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        return listOf(
+            PreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+            SwitchPreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+            MainSwitchPreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+            TwoTargetSwitchPreferencePageProvider.buildInjectEntry()
+                .setLink(fromPage = SettingsPage.create(name)).build(),
+        )
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        PreferenceMain()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun PreferenceMain() {
-    RegularScaffold(title = TITLE) {
-        PreferencePageProvider.EntryItem()
-        SwitchPreferencePageProvider.EntryItem()
-        MainSwitchPreferencePageProvider.EntryItem()
-        TwoTargetSwitchPreferencePageProvider.EntryItem()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index 36c619f..cbd028d 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -29,6 +29,9 @@
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.toState
@@ -44,68 +47,107 @@
 object PreferencePageProvider : SettingsPageProvider {
     override val name = "Preference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create("Preference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Preference"
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Preference with summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Preference"
+                        override val summary = "With summary".toState()
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Preference with async summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Preference"
+                        override val summary = produceState(initialValue = " ") {
+                            delay(1000L)
+                            value = "Async summary"
+                        }
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Click me", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    var count by rememberSaveable { mutableStateOf(0) }
+                    Preference(object : PreferenceModel {
+                        override val title = "Click me"
+                        override val summary = derivedStateOf { count.toString() }
+                        override val onClick: (() -> Unit) = { count++ }
+                        override val icon = @Composable {
+                            SettingsIcon(imageVector = Icons.Outlined.TouchApp)
+                        }
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Ticker", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    var ticks by rememberSaveable { mutableStateOf(0) }
+                    LaunchedEffect(ticks) {
+                        delay(1000L)
+                        ticks++
+                    }
+                    Preference(object : PreferenceModel {
+                        override val title = "Ticker"
+                        override val summary = derivedStateOf { ticks.toString() }
+                    })
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create("Disabled", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    Preference(object : PreferenceModel {
+                        override val title = "Disabled"
+                        override val summary = "Disabled".toState()
+                        override val enabled = false.toState()
+                        override val icon = @Composable {
+                            SettingsIcon(imageVector = Icons.Outlined.DisabledByDefault)
+                        }
+                    })
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        PreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun PreferencePage() {
-    RegularScaffold(title = TITLE) {
-        Preference(object : PreferenceModel {
-            override val title = "Preference"
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Preference"
-            override val summary = "With summary".toState()
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Preference"
-            override val summary = produceState(initialValue = " ") {
-                delay(1000L)
-                value = "Async summary"
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
             }
-        })
-
-        var count by rememberSaveable { mutableStateOf(0) }
-        Preference(object : PreferenceModel {
-            override val title = "Click me"
-            override val summary = derivedStateOf { count.toString() }
-            override val onClick: (() -> Unit) = { count++ }
-            override val icon = @Composable {
-                SettingsIcon(imageVector = Icons.Outlined.TouchApp)
-            }
-        })
-
-        var ticks by rememberSaveable { mutableStateOf(0) }
-        LaunchedEffect(ticks) {
-            delay(1000L)
-            ticks++
         }
-        Preference(object : PreferenceModel {
-            override val title = "Ticker"
-            override val summary = derivedStateOf { ticks.toString() }
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Disabled"
-            override val summary = "Disabled".toState()
-            override val enabled = false.toState()
-            override val icon = @Composable {
-              SettingsIcon(imageVector = Icons.Outlined.DisabledByDefault)
-            }
-        })
     }
 }
 
@@ -113,6 +155,6 @@
 @Composable
 private fun PreferencePagePreview() {
     SettingsTheme {
-        PreferencePage()
+        PreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
index 8be6a89..46b44ca 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
@@ -23,6 +23,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -39,27 +42,59 @@
 object SwitchPreferencePageProvider : SettingsPageProvider {
     override val name = "SwitchPreference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleSwitchPreference()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference with summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleSwitchPreferenceWithSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference with async summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleSwitchPreferenceWithAsyncSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference not changeable", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleNotChangeableSwitchPreference()
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        SampleSwitchPreference()
-        SampleSwitchPreferenceWithSummary()
-        SampleSwitchPreferenceWithAsyncSummary()
-        SampleNotChangeableSwitchPreference()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -123,6 +158,6 @@
 @Composable
 private fun SwitchPreferencePagePreview() {
     SettingsTheme {
-        SwitchPreferencePage()
+        SwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
index 894692b..b991f59 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
@@ -23,6 +23,9 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
@@ -39,27 +42,59 @@
 object TwoTargetSwitchPreferencePageProvider : SettingsPageProvider {
     override val name = "TwoTargetSwitchPreference"
 
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleTwoTargetSwitchPreference()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference with summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleTwoTargetSwitchPreferenceWithSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference with async summary", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleTwoTargetSwitchPreferenceWithAsyncSummary()
+                }.build()
+        )
+        entryList.add(
+            SettingsEntryBuilder.create( "TwoTargetSwitchPreference not changeable", owner)
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    SampleNotChangeableTwoTargetSwitchPreference()
+                }.build()
+        )
+
+        return entryList
+    }
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        TwoTargetSwitchPreferencePage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun TwoTargetSwitchPreferencePage() {
-    RegularScaffold(title = TITLE) {
-        SampleTwoTargetSwitchPreference()
-        SampleTwoTargetSwitchPreferenceWithSummary()
-        SampleTwoTargetSwitchPreferenceWithAsyncSummary()
-        SampleNotChangeableTwoTargetSwitchPreference()
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
     }
 }
 
@@ -123,6 +158,6 @@
 @Composable
 private fun TwoTargetSwitchPreferencePagePreview() {
     SettingsTheme {
-        TwoTargetSwitchPreferencePage()
+        TwoTargetSwitchPreferencePageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
index 7efa85b..03b72d3 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
@@ -23,6 +23,8 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -36,33 +38,33 @@
 object SpinnerPageProvider : SettingsPageProvider {
     override val name = "Spinner"
 
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setIsAllowSearch(true)
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
     @Composable
     override fun Page(arguments: Bundle?) {
-        SpinnerPage()
-    }
-
-    @Composable
-    fun EntryItem() {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val onClick = navigator(name)
-        })
-    }
-}
-
-@Composable
-private fun SpinnerPage() {
-    RegularScaffold(title = TITLE) {
-        val selectedIndex = rememberSaveable { mutableStateOf(0) }
-        Spinner(
-            options = (1..3).map { "Option $it" },
-            selectedIndex = selectedIndex.value,
-            setIndex = { selectedIndex.value = it },
-        )
-        Preference(object : PreferenceModel {
-            override val title = "Selected index"
-            override val summary = remember { derivedStateOf { selectedIndex.value.toString() } }
-        })
+        RegularScaffold(title = TITLE) {
+            val selectedIndex = rememberSaveable { mutableStateOf(0) }
+            Spinner(
+                options = (1..3).map { "Option $it" },
+                selectedIndex = selectedIndex.value,
+                setIndex = { selectedIndex.value = it },
+            )
+            Preference(object : PreferenceModel {
+                override val title = "Selected index"
+                override val summary = remember {
+                    derivedStateOf { selectedIndex.value.toString() }
+                }
+            })
+        }
     }
 }
 
@@ -70,6 +72,6 @@
 @Composable
 private fun SpinnerPagePreview() {
     SettingsTheme {
-        SpinnerPage()
+        SpinnerPageProvider.Page(null)
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp
index 3c8d91e..6871f21 100644
--- a/packages/SettingsLib/Spa/spa/Android.bp
+++ b/packages/SettingsLib/Spa/spa/Android.bp
@@ -27,9 +27,11 @@
         "androidx.compose.material3_material3",
         "androidx.compose.material_material-icons-extended",
         "androidx.compose.runtime_runtime",
+        "androidx.compose.runtime_runtime-livedata",
         "androidx.compose.ui_ui-tooling-preview",
         "androidx.navigation_navigation-compose",
         "com.google.android.material_material",
+        "lottie_compose",
     ],
     kotlincflags: [
         "-Xjvm-default=all",
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 104966d..418d6cb 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -59,6 +59,7 @@
 }
 
 dependencies {
+    api "androidx.appcompat:appcompat:1.6.0-rc01"
     api "androidx.compose.material3:material3:$jetpack_compose_material3_version"
     api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
     api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index 87d4f5a..e5a1862 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -22,11 +22,16 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.navigation.NavGraph.Companion.findStartDestination
+import androidx.navigation.NavHostController
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
 import androidx.navigation.compose.rememberNavController
+import androidx.navigation.navArgument
 import com.android.settingslib.spa.R
+import com.android.settingslib.spa.framework.common.ROOT_PAGE_NAME
 import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
 import com.android.settingslib.spa.framework.compose.localNavController
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -48,27 +53,40 @@
 
     @Composable
     private fun MainContent() {
-        val destination = intent?.getStringExtra(KEY_DESTINATION)
-
         val navController = rememberNavController()
         CompositionLocalProvider(navController.localNavController()) {
-            NavHost(navController, sppRepository.getDefaultStartPageName()) {
+            NavHost(navController, ROOT_PAGE_NAME) {
+                composable(ROOT_PAGE_NAME) {}
                 for (page in sppRepository.getAllProviders()) {
                     composable(
-                        route = page.name + page.parameter.navRoute(),
-                        arguments = page.parameter,
+                        route = page.name + page.parameter.navRoute() +
+                            "?$HIGHLIGHT_ENTRY_PARAM_NAME={$HIGHLIGHT_ENTRY_PARAM_NAME}",
+                        arguments = page.parameter + listOf(
+                            // add optional parameters
+                            navArgument(HIGHLIGHT_ENTRY_PARAM_NAME) { defaultValue = "null" }
+                        ),
                     ) { navBackStackEntry ->
                         page.Page(navBackStackEntry.arguments)
                     }
                 }
             }
+        }
 
-            if (!destination.isNullOrEmpty()) {
-                LaunchedEffect(Unit) {
-                    navController.navigate(destination) {
-                        popUpTo(navController.graph.findStartDestination().id) {
-                            inclusive = true
-                        }
+        InitialDestinationNavigator(navController)
+    }
+
+    @Composable
+    private fun InitialDestinationNavigator(navController: NavHostController) {
+        val destinationNavigated = rememberSaveable { mutableStateOf(false) }
+        if (destinationNavigated.value) return
+        destinationNavigated.value = true
+        LaunchedEffect(Unit) {
+            val destination =
+                intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPageName()
+            if (destination.isNotEmpty()) {
+                navController.navigate(destination) {
+                    popUpTo(navController.graph.findStartDestination().id) {
+                        inclusive = true
                     }
                 }
             }
@@ -77,5 +95,6 @@
 
     companion object {
         const val KEY_DESTINATION = "spa:SpaActivity:destination"
+        const val HIGHLIGHT_ENTRY_PARAM_NAME = "highlightEntry"
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
new file mode 100644
index 0000000..8aef2c6
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+import androidx.navigation.NavType
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import androidx.navigation.navArgument
+import com.android.settingslib.spa.R
+import com.android.settingslib.spa.framework.BrowseActivity.Companion.KEY_DESTINATION
+import com.android.settingslib.spa.framework.EntryProvider.Companion.PAGE_INFO_QUERY
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryRepository
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.compose.localNavController
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.toState
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.HomeScaffold
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+
+private const val ROUTE_ROOT = "root"
+private const val ROUTE_All_PAGES = "pages"
+private const val ROUTE_All_ENTRIES = "entries"
+private const val ROUTE_PAGE = "page"
+private const val ROUTE_ENTRY = "entry"
+private const val PARAM_NAME_PAGE_ID = "pid"
+private const val PARAM_NAME_ENTRY_ID = "eid"
+
+open class DebugActivity(
+    private val entryRepository: SettingsEntryRepository,
+    private val browseActivityClass: Class<*>,
+    private val entryProviderAuthorities: String? = null,
+) : ComponentActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        setTheme(R.style.Theme_SpaLib_DayNight)
+        super.onCreate(savedInstanceState)
+        displayDebugMessage()
+
+        setContent {
+            SettingsTheme {
+                MainContent()
+            }
+        }
+    }
+
+    private fun displayDebugMessage() {
+        if (entryProviderAuthorities == null) return
+
+        try {
+            contentResolver.query(
+                Uri.parse("content://$entryProviderAuthorities/${PAGE_INFO_QUERY.queryPath}"),
+                null, null, null
+            ).use { cursor ->
+                while (cursor != null && cursor.moveToNext()) {
+                    val route = cursor.getString(PAGE_INFO_QUERY.getIndex(ColumnName.PAGE_ROUTE))
+                    val entryCount = cursor.getInt(PAGE_INFO_QUERY.getIndex(ColumnName.ENTRY_COUNT))
+                    val hasRuntimeParam =
+                        cursor.getInt(PAGE_INFO_QUERY.getIndex(ColumnName.HAS_RUNTIME_PARAM)) == 1
+                    Log.d(
+                        "DEBUG ACTIVITY", "Page Info: $route ($entryCount) " +
+                            (if (hasRuntimeParam) "with" else "no") + "-runtime-params"
+                    )
+                }
+            }
+        } catch (e: Exception) {
+            Log.e("DEBUG ACTIVITY", "Provider querying exception:", e)
+        }
+    }
+
+    @Composable
+    private fun MainContent() {
+        val navController = rememberNavController()
+        CompositionLocalProvider(navController.localNavController()) {
+            NavHost(navController, ROUTE_ROOT) {
+                composable(route = ROUTE_ROOT) { RootPage() }
+                composable(route = ROUTE_All_PAGES) { AllPages() }
+                composable(route = ROUTE_All_ENTRIES) { AllEntries() }
+                composable(
+                    route = "$ROUTE_PAGE/{$PARAM_NAME_PAGE_ID}",
+                    arguments = listOf(
+                        navArgument(PARAM_NAME_PAGE_ID) { type = NavType.IntType },
+                    )
+                ) { navBackStackEntry -> OnePage(navBackStackEntry.arguments) }
+                composable(
+                    route = "$ROUTE_ENTRY/{$PARAM_NAME_ENTRY_ID}",
+                    arguments = listOf(
+                        navArgument(PARAM_NAME_ENTRY_ID) { type = NavType.IntType },
+                    )
+                ) { navBackStackEntry -> OneEntry(navBackStackEntry.arguments) }
+            }
+        }
+    }
+
+    @Composable
+    fun RootPage() {
+        HomeScaffold(title = "Settings Debug") {
+            Preference(object : PreferenceModel {
+                override val title = "List All Pages"
+                override val onClick = navigator(route = ROUTE_All_PAGES)
+            })
+            Preference(object : PreferenceModel {
+                override val title = "List All Entries"
+                override val onClick = navigator(route = ROUTE_All_ENTRIES)
+            })
+        }
+    }
+
+    @Composable
+    fun AllPages() {
+        RegularScaffold(title = "All Pages") {
+            for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
+                Preference(object : PreferenceModel {
+                    override val title =
+                        "${pageWithEntry.page.name} (${pageWithEntry.entries.size})"
+                    override val summary = pageWithEntry.page.formatArguments().toState()
+                    override val onClick =
+                        navigator(route = ROUTE_PAGE + "/${pageWithEntry.page.id}")
+                })
+            }
+        }
+    }
+
+    @Composable
+    fun AllEntries() {
+        RegularScaffold(title = "All Entries") {
+            EntryList(entryRepository.getAllEntries())
+        }
+    }
+
+    @Composable
+    fun OnePage(arguments: Bundle?) {
+        val id = arguments!!.getInt(PARAM_NAME_PAGE_ID)
+        val pageWithEntry = entryRepository.getPageWithEntry(id)!!
+        RegularScaffold(title = "Page ${pageWithEntry.page.name}") {
+            Text(text = pageWithEntry.page.formatArguments())
+            Text(text = "Entry size: ${pageWithEntry.entries.size}")
+            Preference(model = object : PreferenceModel {
+                override val title = "open page"
+                override val enabled = (!pageWithEntry.page.hasRuntimeParam()).toState()
+                override val onClick = openPage(pageWithEntry.page)
+            })
+            EntryList(pageWithEntry.entries)
+        }
+    }
+
+    @Composable
+    fun OneEntry(arguments: Bundle?) {
+        val id = arguments!!.getInt(PARAM_NAME_ENTRY_ID)
+        val entry = entryRepository.getEntry(id)!!
+        RegularScaffold(title = "Entry ${entry.displayName()}") {
+            Preference(model = object : PreferenceModel {
+                override val title = "open entry"
+                override val enabled = (!entry.hasRuntimeParam()).toState()
+                override val onClick = openEntry(entry)
+            })
+            Text(text = entry.formatAll())
+        }
+    }
+
+    @Composable
+    private fun EntryList(entries: Collection<SettingsEntry>) {
+        for (entry in entries) {
+            Preference(object : PreferenceModel {
+                override val title = entry.displayName()
+                override val summary =
+                    "${entry.fromPage?.name} -> ${entry.toPage?.name}".toState()
+                override val onClick = navigator(route = ROUTE_ENTRY + "/${entry.id}")
+            })
+        }
+    }
+
+    @Composable
+    private fun openPage(page: SettingsPage): (() -> Unit)? {
+        if (page.hasRuntimeParam()) return null
+        val route = page.buildRoute()
+        val context = LocalContext.current
+        val intent = Intent(context, browseActivityClass).apply {
+            putExtra(KEY_DESTINATION, route)
+        }
+        return {
+            Log.d("DEBUG ACTIVITY", "Open page: $route")
+            context.startActivity(intent)
+        }
+    }
+
+    @Composable
+    private fun openEntry(entry: SettingsEntry): (() -> Unit)? {
+        if (entry.hasRuntimeParam()) return null
+        val route = entry.buildRoute()
+        val context = LocalContext.current
+        val intent = Intent(context, browseActivityClass).apply {
+            putExtra(KEY_DESTINATION, route)
+        }
+        return {
+            Log.d("DEBUG ACTIVITY", "Open entry: $route")
+            context.startActivity(intent)
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt
new file mode 100644
index 0000000..90ce182
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/EntryProvider.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.content.Context
+import android.content.UriMatcher
+import android.content.pm.ProviderInfo
+import android.database.Cursor
+import android.database.MatrixCursor
+import android.net.Uri
+import android.util.Log
+import com.android.settingslib.spa.framework.common.SettingsEntryRepository
+
+/**
+ * Enum to define all column names in provider.
+ */
+enum class ColumnName(val id: String) {
+    PAGE_NAME("pageName"),
+    PAGE_ROUTE("pageRoute"),
+    ENTRY_COUNT("entryCount"),
+    HAS_RUNTIME_PARAM("hasRuntimeParam"),
+    PAGE_START_ADB("pageStartAdb"),
+}
+
+data class QueryDefinition(
+    val queryPath: String,
+    val queryMatchCode: Int,
+    val columnNames: List<ColumnName>,
+) {
+    fun getColumns(): Array<String> {
+        return columnNames.map { it.id }.toTypedArray()
+    }
+
+    fun getIndex(name: ColumnName): Int {
+        return columnNames.indexOf(name)
+    }
+}
+
+open class EntryProvider(
+    private val entryRepository: SettingsEntryRepository,
+    private val browseActivityComponentName: String? = null,
+) : ContentProvider() {
+
+    private var mMatcher: UriMatcher? = null
+
+    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
+        TODO("Implement this to handle requests to delete one or more rows")
+    }
+
+    override fun getType(uri: Uri): String? {
+        TODO(
+            "Implement this to handle requests for the MIME type of the data" +
+                "at the given URI"
+        )
+    }
+
+    override fun insert(uri: Uri, values: ContentValues?): Uri? {
+        TODO("Implement this to handle requests to insert a new row.")
+    }
+
+    override fun update(
+        uri: Uri,
+        values: ContentValues?,
+        selection: String?,
+        selectionArgs: Array<String>?
+    ): Int {
+        TODO("Implement this to handle requests to update one or more rows.")
+    }
+
+    override fun onCreate(): Boolean {
+        return true
+    }
+
+    override fun attachInfo(context: Context?, info: ProviderInfo?) {
+        mMatcher = UriMatcher(UriMatcher.NO_MATCH)
+        if (info != null) {
+            mMatcher!!.addURI(
+                info.authority,
+                PAGE_START_COMMAND_QUERY.queryPath,
+                PAGE_START_COMMAND_QUERY.queryMatchCode
+            )
+            mMatcher!!.addURI(
+                info.authority,
+                PAGE_INFO_QUERY.queryPath,
+                PAGE_INFO_QUERY.queryMatchCode
+            )
+        }
+        super.attachInfo(context, info)
+    }
+
+    override fun query(
+        uri: Uri,
+        projection: Array<String>?,
+        selection: String?,
+        selectionArgs: Array<String>?,
+        sortOrder: String?
+    ): Cursor? {
+        return try {
+            when (mMatcher!!.match(uri)) {
+                PAGE_START_COMMAND_QUERY.queryMatchCode -> queryPageStartCommand()
+                PAGE_INFO_QUERY.queryMatchCode -> queryPageInfo()
+                else -> throw UnsupportedOperationException("Unknown Uri $uri")
+            }
+        } catch (e: UnsupportedOperationException) {
+            throw e
+        } catch (e: Exception) {
+            Log.e("EntryProvider", "Provider querying exception:", e)
+            null
+        }
+    }
+
+    private fun queryPageStartCommand(): Cursor {
+        val componentName = browseActivityComponentName ?: "[component-name]"
+        val cursor = MatrixCursor(PAGE_START_COMMAND_QUERY.getColumns())
+        for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
+            val page = pageWithEntry.page
+            if (!page.hasRuntimeParam()) {
+                cursor.newRow().add(
+                    ColumnName.PAGE_START_ADB.id,
+                    "adb shell am start -n $componentName" +
+                        " -e ${BrowseActivity.KEY_DESTINATION} ${page.buildRoute()}"
+                )
+            }
+        }
+        return cursor
+    }
+
+    private fun queryPageInfo(): Cursor {
+        val cursor = MatrixCursor(PAGE_INFO_QUERY.getColumns())
+        for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
+            val page = pageWithEntry.page
+            cursor.newRow().add(ColumnName.PAGE_NAME.id, page.name)
+                .add(ColumnName.PAGE_ROUTE.id, page.buildRoute())
+                .add(ColumnName.ENTRY_COUNT.id, pageWithEntry.entries.size)
+                .add(ColumnName.HAS_RUNTIME_PARAM.id, if (page.hasRuntimeParam()) 1 else 0)
+        }
+        return cursor
+    }
+
+    companion object {
+        val PAGE_START_COMMAND_QUERY = QueryDefinition(
+            "page_start", 1,
+            listOf(ColumnName.PAGE_START_ADB)
+        )
+
+        val PAGE_INFO_QUERY = QueryDefinition(
+            "page_info", 2,
+            listOf(
+                ColumnName.PAGE_NAME,
+                ColumnName.PAGE_ROUTE,
+                ColumnName.ENTRY_COUNT,
+                ColumnName.HAS_RUNTIME_PARAM,
+            )
+        )
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 98734da..445c4eb 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -19,10 +19,13 @@
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.navigation.NamedNavArgument
-import com.android.settingslib.spa.framework.util.normalize
+import androidx.navigation.NavType
+import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.util.navLink
 
 const val INJECT_ENTRY_NAME = "INJECT"
 const val ROOT_ENTRY_NAME = "ROOT"
+const val ROOT_PAGE_NAME = "Root"
 
 /**
  * Defines data of one Settings entry for Settings search.
@@ -37,36 +40,64 @@
 /**
  * Defines data to identify a Settings page.
  */
-data class SettingsPage(val name: String = "", val arguments: Bundle? = null) {
-    override fun toString(): String {
-        val argsStr = arguments?.toString()?.removeRange(0, 6) ?: ""
-        return name + argsStr
-    }
+data class SettingsPage(
+    // The unique id of this page, which is computed by name + normalized(arguments)
+    val id: Int,
 
+    // The name of the page, which is used to compute the unique id, and need to be stable.
+    val name: String,
+
+    // Defined parameters of this page.
+    val parameter: List<NamedNavArgument> = emptyList(),
+
+    // The arguments of this page.
+    val arguments: Bundle? = null,
+) {
     companion object {
         fun create(
             name: String,
             parameter: List<NamedNavArgument> = emptyList(),
             arguments: Bundle? = null
         ): SettingsPage {
-            return SettingsPage(name, parameter.normalize(arguments))
+            return SettingsPageBuilder(name, parameter).setArguments(arguments).build()
         }
     }
+
+    fun formatArguments(): String {
+        val normalizedArguments = parameter.normalize(arguments)
+        if (normalizedArguments == null || normalizedArguments.isEmpty) return "[No arguments]"
+        return normalizedArguments.toString().removeRange(0, 6)
+    }
+
+    fun formatAll(): String {
+        return "$name ${formatArguments()}"
+    }
+
+    fun buildRoute(highlightEntryName: String? = null): String {
+        val highlightParam =
+            if (highlightEntryName == null)
+                ""
+            else
+                "?${BrowseActivity.HIGHLIGHT_ENTRY_PARAM_NAME}=$highlightEntryName"
+        return name + parameter.navLink(arguments) + highlightParam
+    }
+
+    fun hasRuntimeParam(): Boolean {
+        return parameter.hasRuntimeParam(arguments)
+    }
 }
 
 /**
  * Defines data of a Settings entry.
  */
 data class SettingsEntry(
-    // The unique id of this entry.
-    // By default, it is computed by name + owner + fromPage + toPage
-    val id: String,
+    // The unique id of this entry, which is computed by name + owner + fromPage + toPage.
+    val id: Int,
 
-    // The display name of this entry, which is used to be shown in hierarchy.
-    // By default, it is computed by name + owner
-    val displayName: String,
-
+    // The name of the page, which is used to compute the unique id, and need to be stable.
     val name: String,
+
+    // The owner page of this entry.
     val owner: SettingsPage,
 
     // Defines linking of Settings entries
@@ -104,10 +135,68 @@
      * injected entry. In the long term, we may deprecate the @Composable Page() API in SPP, and
      * use each entries' UI rendering function in the page instead.
      */
-    val uiLayout: (@Composable () -> Unit) = {},
+    val uiLayoutImpl: (@Composable (arguments: Bundle?) -> Unit) = {},
 ) {
-    override fun toString(): String {
-        return displayName + "(${fromPage?.toString()}->${toPage?.toString()})"
+    fun formatAll(): String {
+        val content = listOf(
+            "owner = ${owner.formatAll()}",
+            "linkFrom = ${fromPage?.formatAll()}",
+            "linkTo = ${toPage?.formatAll()}",
+        )
+        return content.joinToString("\n")
+    }
+
+    // The display name of the entry, for better readability.
+    fun displayName(): String {
+        return "${owner.name}:$name"
+    }
+
+    private fun getDisplayPage(): SettingsPage {
+        // Display the entry on its from-page, or on its owner page if the from-page is unset.
+        return fromPage ?: owner
+    }
+
+    fun buildRoute(): String {
+        return getDisplayPage().buildRoute(name)
+    }
+
+    fun hasRuntimeParam(): Boolean {
+        return getDisplayPage().hasRuntimeParam()
+    }
+
+    @Composable
+    fun UiLayout(runtimeArguments: Bundle? = null) {
+        val arguments = Bundle()
+        if (owner.arguments != null) arguments.putAll(owner.arguments)
+        if (runtimeArguments != null) arguments.putAll(runtimeArguments)
+        uiLayoutImpl(arguments)
+    }
+}
+
+data class SettingsPageWithEntry(
+    val page: SettingsPage,
+    val entries: List<SettingsEntry>,
+)
+
+class SettingsPageBuilder(
+    private val name: String,
+    private val parameter: List<NamedNavArgument> = emptyList()
+) {
+    private var arguments: Bundle? = null
+
+    fun build(): SettingsPage {
+        val normArguments = parameter.normalize(arguments)
+        return SettingsPage(
+            id = "$name:${normArguments?.toString()}".toUniqueId(),
+            name = name,
+            parameter = parameter,
+            arguments = arguments,
+        )
+    }
+
+    fun setArguments(arguments: Bundle?): SettingsPageBuilder {
+        this.arguments = arguments
+        return this
     }
 }
 
@@ -115,19 +204,16 @@
  * The helper to build a Settings Entry instance.
  */
 class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
-    private var uniqueId: String? = null
-    private var displayName: String? = null
     private var fromPage: SettingsPage? = null
     private var toPage: SettingsPage? = null
     private var isAllowSearch: Boolean? = null
 
     private var searchDataFn: () -> SearchData? = { null }
-    private var uiLayoutFn: (@Composable () -> Unit) = {}
+    private var uiLayoutFn: (@Composable (arguments: Bundle?) -> Unit) = {}
 
     fun build(): SettingsEntry {
         return SettingsEntry(
-            id = computeUniqueId(),
-            displayName = computeDisplayName(),
+            id = "$name:${owner.id}(${fromPage?.id}-${toPage?.id})".toUniqueId(),
             name = name,
             owner = owner,
 
@@ -136,11 +222,11 @@
             toPage = toPage,
 
             // attributes
-            isAllowSearch = computeSearchable(),
+            isAllowSearch = getIsSearchable(),
 
             // functions
             searchData = searchDataFn,
-            uiLayout = uiLayoutFn,
+            uiLayoutImpl = uiLayoutFn,
         )
     }
 
@@ -163,17 +249,12 @@
         return this
     }
 
-    fun setUiLayoutFn(fn: @Composable () -> Unit): SettingsEntryBuilder {
+    fun setUiLayoutFn(fn: @Composable (arguments: Bundle?) -> Unit): SettingsEntryBuilder {
         this.uiLayoutFn = fn
         return this
     }
 
-    private fun computeUniqueId(): String =
-        uniqueId ?: "$owner:$name" + fromPage?.toString() + toPage?.toString()
-
-    private fun computeDisplayName(): String = displayName ?: "$owner:$name"
-
-    private fun computeSearchable(): Boolean = isAllowSearch ?: false
+    private fun getIsSearchable(): Boolean = isAllowSearch ?: false
 
     companion object {
         fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
@@ -188,12 +269,48 @@
             return create(entryName, owner).setLink(toPage = owner)
         }
 
-        fun createInject(owner: SettingsPage): SettingsEntryBuilder {
-            return createLinkTo(INJECT_ENTRY_NAME, owner)
+        fun createInject(owner: SettingsPage, entryName: String? = null): SettingsEntryBuilder {
+            val name = entryName ?: "${INJECT_ENTRY_NAME}_${owner.name}"
+            return createLinkTo(name, owner)
         }
 
-        fun createRoot(page: SettingsPage): SettingsEntryBuilder {
-            return createLinkTo(ROOT_ENTRY_NAME, page)
+        fun createRoot(owner: SettingsPage, entryName: String? = null): SettingsEntryBuilder {
+            val name = entryName ?: "${ROOT_ENTRY_NAME}_${owner.name}"
+            return createLinkTo(name, owner)
         }
     }
 }
+
+private fun String.toUniqueId(): Int {
+    return this.hashCode()
+}
+
+private fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
+    if (this.isEmpty()) return null
+    val normArgs = Bundle()
+    for (navArg in this) {
+        when (navArg.argument.type) {
+            NavType.StringType -> {
+                val value = arguments?.getString(navArg.name)
+                if (value != null)
+                    normArgs.putString(navArg.name, value)
+                else
+                    normArgs.putString("unset_" + navArg.name, null)
+            }
+            NavType.IntType -> {
+                if (arguments != null && arguments.containsKey(navArg.name))
+                    normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
+                else
+                    normArgs.putString("unset_" + navArg.name, null)
+            }
+        }
+    }
+    return normArgs
+}
+
+private fun List<NamedNavArgument>.hasRuntimeParam(arguments: Bundle? = null): Boolean {
+    for (navArg in this) {
+        if (arguments == null || !arguments.containsKey(navArg.name)) return true
+    }
+    return false
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
index e3a55e5..a4e5a58 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -26,19 +26,19 @@
  */
 class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
     // Map of entry unique Id to entry
-    private val entryMap: Map<String, SettingsEntry>
+    private val entryMap: Map<Int, SettingsEntry>
 
     // Map of Settings page to its contained entries.
-    private val pageToEntryListMap: Map<String, List<SettingsEntry>>
+    private val pageWithEntryMap: Map<Int, SettingsPageWithEntry>
 
     init {
         logMsg("Initialize")
         entryMap = mutableMapOf()
-        pageToEntryListMap = mutableMapOf()
+        pageWithEntryMap = mutableMapOf()
 
         val entryQueue = LinkedList<SettingsEntry>()
         for (page in sppRepository.getAllRootPages()) {
-            val rootEntry = SettingsEntryBuilder.createRoot(page).build()
+            val rootEntry = SettingsEntryBuilder.createRoot(owner = page).build()
             if (!entryMap.containsKey(rootEntry.id)) {
                 entryQueue.push(rootEntry)
                 entryMap.put(rootEntry.id, rootEntry)
@@ -48,10 +48,10 @@
         while (entryQueue.isNotEmpty() && entryMap.size < MAX_ENTRY_SIZE) {
             val entry = entryQueue.pop()
             val page = entry.toPage
-            if (page == null || pageToEntryListMap.containsKey(page.toString())) continue
+            if (page == null || pageWithEntryMap.containsKey(page.id)) continue
             val spp = sppRepository.getProviderOrNull(page.name) ?: continue
             val newEntries = spp.buildEntry(page.arguments)
-            pageToEntryListMap[page.toString()] = newEntries
+            pageWithEntryMap[page.id] = SettingsPageWithEntry(page, newEntries)
             for (newEntry in newEntries) {
                 if (!entryMap.containsKey(newEntry.id)) {
                     entryQueue.push(newEntry)
@@ -60,19 +60,23 @@
             }
         }
 
-        logMsg("Initialize Completed: ${entryMap.size} entries in ${pageToEntryListMap.size} pages")
+        logMsg("Initialize Completed: ${entryMap.size} entries in ${pageWithEntryMap.size} pages")
     }
 
-    fun printAllPages() {
-        for (entry in pageToEntryListMap.entries) {
-            logMsg("page: ${entry.key} with ${entry.value.size} entries")
-        }
+    fun getAllPageWithEntry(): Collection<SettingsPageWithEntry> {
+        return pageWithEntryMap.values
     }
 
-    fun printAllEntries() {
-        for (entry in entryMap.values) {
-            logMsg("entry: $entry")
-        }
+    fun getPageWithEntry(pageId: Int): SettingsPageWithEntry? {
+        return pageWithEntryMap[pageId]
+    }
+
+    fun getAllEntries(): Collection<SettingsEntry> {
+        return entryMap.values
+    }
+
+    fun getEntry(entryId: Int): SettingsEntry? {
+        return entryMap[entryId]
     }
 }
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
index 4e768eb..d7d7750 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
@@ -25,9 +25,12 @@
 }
 
 fun List<NamedNavArgument>.navLink(arguments: Bundle? = null): String {
-    if (arguments == null) return ""
     val argsArray = mutableListOf<String>()
     for (navArg in this) {
+        if (arguments == null || !arguments.containsKey(navArg.name)) {
+            argsArray.add("[rt]")
+            continue
+        }
         when (navArg.argument.type) {
             NavType.StringType -> {
                 argsArray.add(arguments.getString(navArg.name, ""))
@@ -40,29 +43,6 @@
     return argsArray.joinToString("") { arg -> "/$arg" }
 }
 
-fun List<NamedNavArgument>.normalize(arguments: Bundle? = null): Bundle? {
-    if (this.isEmpty()) return null
-    val normArgs = Bundle()
-    for (navArg in this) {
-        when (navArg.argument.type) {
-            NavType.StringType -> {
-                val value = arguments?.getString(navArg.name)
-                if (value != null)
-                    normArgs.putString(navArg.name, value)
-                else
-                    normArgs.putString("unset_" + navArg.name, null)
-            }
-            NavType.IntType -> {
-                if (arguments != null && arguments.containsKey(navArg.name))
-                    normArgs.putInt(navArg.name, arguments.getInt(navArg.name))
-                else
-                    normArgs.putString("unset_" + navArg.name, null)
-            }
-        }
-    }
-    return normArgs
-}
-
 fun List<NamedNavArgument>.getStringArg(name: String, arguments: Bundle? = null): String? {
     if (this.containsStringArg(name) && arguments != null) {
         return arguments.getString(name)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt
index 0d4e0c5..cd8a02a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt
@@ -29,7 +29,7 @@
 import androidx.compose.ui.draw.clip
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.widget.ui.ImageBox
-
+import com.android.settingslib.spa.widget.ui.Lottie
 enum class ResourceType { IMAGE, LOTTIE }
 
 /**
@@ -72,7 +72,7 @@
     Column(
         modifier = modifier
             .fillMaxWidth()
-            .padding(SettingsDimension.illustrationPadding),
+            .padding(horizontal = SettingsDimension.illustrationPadding),
         horizontalAlignment = Alignment.CenterHorizontally,
     ) {
         val illustrationModifier = modifier
@@ -85,7 +85,10 @@
 
         when (resourceType) {
             ResourceType.LOTTIE -> {
-                // TODO: Add Lottie function after lottie is enabled.
+                Lottie(
+                    resId = resId,
+                    modifier = illustrationModifier,
+                )
             }
             ResourceType.IMAGE -> {
                 ImageBox(
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Lottie.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Lottie.kt
new file mode 100644
index 0000000..915c6e2
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Lottie.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.ui
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import com.airbnb.lottie.compose.LottieAnimation
+import com.airbnb.lottie.compose.LottieCompositionSpec
+import com.airbnb.lottie.compose.LottieConstants
+import com.airbnb.lottie.compose.animateLottieCompositionAsState
+import com.airbnb.lottie.compose.rememberLottieComposition
+
+@Composable
+fun Lottie(
+    resId: Int,
+    modifier: Modifier = Modifier,
+) {
+    Box(
+        modifier = modifier,
+    ) {
+        BaseLottie(resId)
+    }
+}
+
+@Composable
+private fun BaseLottie(resId: Int) {
+    val composition by rememberLottieComposition(
+        LottieCompositionSpec.RawRes(resId)
+    )
+    val progress by animateLottieCompositionAsState(
+        composition,
+        iterations = LottieConstants.IterateForever,
+    )
+    LottieAnimation(
+        composition = composition,
+        progress = { progress },
+    )
+}
diff --git a/packages/SettingsLib/Spa/tests/res/raw/accessibility_shortcut_type_triple_tap.json b/packages/SettingsLib/Spa/tests/res/raw/accessibility_shortcut_type_triple_tap.json
new file mode 100644
index 0000000..870e671
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/res/raw/accessibility_shortcut_type_triple_tap.json
@@ -0,0 +1,1959 @@
+{
+  "v": "5.6.5",
+  "fr": 60,
+  "ip": 0,
+  "op": 180,
+  "w": 412,
+  "h": 300,
+  "nm": "Triple_Tap_Screen",
+  "ddd": 0,
+  "assets": [
+    {
+      "id": "comp_0",
+      "layers": [
+        {
+          "ddd": 0,
+          "ind": 1,
+          "ty": 4,
+          "nm": ".white",
+          "cl": "white",
+          "hd": true,
+          "sr": 1,
+          "ks": {
+            "o": {
+              "a": 0,
+              "k": 100,
+              "ix": 11
+            },
+            "r": {
+              "a": 0,
+              "k": 0,
+              "ix": 10
+            },
+            "p": {
+              "a": 0,
+              "k": [
+                206,
+                150,
+                0
+              ],
+              "ix": 2
+            },
+            "a": {
+              "a": 0,
+              "k": [
+                0,
+                0,
+                0
+              ],
+              "ix": 1
+            },
+            "s": {
+              "a": 0,
+              "k": [
+                100,
+                100,
+                100
+              ],
+              "ix": 6
+            }
+          },
+          "ao": 0,
+          "shapes": [
+            {
+              "ty": "gr",
+              "it": [
+                {
+                  "ind": 0,
+                  "ty": "sh",
+                  "ix": 1,
+                  "ks": {
+                    "a": 0,
+                    "k": {
+                      "i": [
+                        [
+                          15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          15.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          -15.4
+                        ],
+                        [
+                          0,
+                          0
+                        ]
+                      ],
+                      "o": [
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          -15.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          15.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          15.4
+                        ]
+                      ],
+                      "v": [
+                        [
+                          178,
+                          150
+                        ],
+                        [
+                          -178,
+                          150
+                        ],
+                        [
+                          -206,
+                          122
+                        ],
+                        [
+                          -206,
+                          -122
+                        ],
+                        [
+                          -178,
+                          -150
+                        ],
+                        [
+                          178,
+                          -150
+                        ],
+                        [
+                          206,
+                          -122
+                        ],
+                        [
+                          206,
+                          122
+                        ]
+                      ],
+                      "c": true
+                    },
+                    "ix": 2
+                  },
+                  "nm": "Path 1",
+                  "mn": "ADBE Vector Shape - Group",
+                  "hd": false
+                },
+                {
+                  "ty": "fl",
+                  "c": {
+                    "a": 0,
+                    "k": [
+                      1,
+                      1,
+                      1,
+                      1
+                    ],
+                    "ix": 4
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 5
+                  },
+                  "r": 1,
+                  "bm": 0,
+                  "nm": "Fill 1",
+                  "mn": "ADBE Vector Graphic - Fill",
+                  "hd": false
+                },
+                {
+                  "ty": "tr",
+                  "p": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 2
+                  },
+                  "a": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 1
+                  },
+                  "s": {
+                    "a": 0,
+                    "k": [
+                      100,
+                      100
+                    ],
+                    "ix": 3
+                  },
+                  "r": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 6
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 7
+                  },
+                  "sk": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 4
+                  },
+                  "sa": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 5
+                  },
+                  "nm": "Transform"
+                }
+              ],
+              "nm": "Group 1",
+              "np": 2,
+              "cix": 2,
+              "bm": 0,
+              "ix": 1,
+              "mn": "ADBE Vector Group",
+              "hd": false
+            }
+          ],
+          "ip": 0,
+          "op": 1800,
+          "st": 0,
+          "bm": 0
+        }
+      ]
+    }
+  ],
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 1,
+      "ty": 4,
+      "nm": ".grey200",
+      "cl": "grey200",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            206,
+            150,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            1.35,
+            0,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "ind": 0,
+              "ty": "sh",
+              "ix": 1,
+              "ks": {
+                "a": 0,
+                "k": {
+                  "i": [
+                    [
+                      0,
+                      0
+                    ],
+                    [
+                      0,
+                      -73.4
+                    ],
+                    [
+                      -73.4,
+                      0
+                    ],
+                    [
+                      0,
+                      73.4
+                    ],
+                    [
+                      73.4,
+                      0
+                    ]
+                  ],
+                  "o": [
+                    [
+                      -73.4,
+                      0
+                    ],
+                    [
+                      0,
+                      73.4
+                    ],
+                    [
+                      73.4,
+                      0
+                    ],
+                    [
+                      0,
+                      -73.4
+                    ],
+                    [
+                      0,
+                      0
+                    ]
+                  ],
+                  "v": [
+                    [
+                      1.4,
+                      -132.9
+                    ],
+                    [
+                      -131.6,
+                      0
+                    ],
+                    [
+                      1.3,
+                      132.9
+                    ],
+                    [
+                      134.3,
+                      0
+                    ],
+                    [
+                      1.4,
+                      -132.9
+                    ]
+                  ],
+                  "c": true
+                },
+                "ix": 2
+              },
+              "nm": "Path 1",
+              "mn": "ADBE Vector Shape - Group",
+              "hd": false
+            },
+            {
+              "ind": 1,
+              "ty": "sh",
+              "ix": 2,
+              "ks": {
+                "a": 0,
+                "k": {
+                  "i": [
+                    [
+                      0,
+                      0
+                    ],
+                    [
+                      -24.7,
+                      -24.8
+                    ],
+                    [
+                      0,
+                      -35
+                    ],
+                    [
+                      24.8,
+                      -24.7
+                    ],
+                    [
+                      35,
+                      0
+                    ],
+                    [
+                      24.7,
+                      24.8
+                    ],
+                    [
+                      0,
+                      35
+                    ],
+                    [
+                      -24.8,
+                      24.7
+                    ],
+                    [
+                      -35,
+                      0
+                    ]
+                  ],
+                  "o": [
+                    [
+                      35,
+                      0
+                    ],
+                    [
+                      24.7,
+                      24.7
+                    ],
+                    [
+                      0,
+                      35
+                    ],
+                    [
+                      -24.7,
+                      24.7
+                    ],
+                    [
+                      -35,
+                      0
+                    ],
+                    [
+                      -24.7,
+                      -24.8
+                    ],
+                    [
+                      0,
+                      -35
+                    ],
+                    [
+                      24.7,
+                      -24.7
+                    ],
+                    [
+                      0,
+                      0
+                    ]
+                  ],
+                  "v": [
+                    [
+                      1.4,
+                      -130.9
+                    ],
+                    [
+                      94,
+                      -92.5
+                    ],
+                    [
+                      132.4,
+                      0.1
+                    ],
+                    [
+                      94,
+                      92.7
+                    ],
+                    [
+                      1.4,
+                      131.1
+                    ],
+                    [
+                      -91.2,
+                      92.7
+                    ],
+                    [
+                      -129.6,
+                      0
+                    ],
+                    [
+                      -91.2,
+                      -92.6
+                    ],
+                    [
+                      1.4,
+                      -130.9
+                    ]
+                  ],
+                  "c": false
+                },
+                "ix": 2
+              },
+              "nm": "Path 2",
+              "mn": "ADBE Vector Shape - Group",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  0.909803926945,
+                  0.917647063732,
+                  0.929411768913,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Group 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 0,
+      "op": 300,
+      "st": 0,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 2,
+      "ty": 4,
+      "nm": ".grey300",
+      "cl": "grey300",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            205,
+            150,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            0,
+            0,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "ty": "gr",
+              "it": [
+                {
+                  "ind": 0,
+                  "ty": "sh",
+                  "ix": 1,
+                  "ks": {
+                    "a": 0,
+                    "k": {
+                      "i": [
+                        [
+                          -7.9,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          8
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          1.6
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          2,
+                          1.5
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          6.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          6.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          1,
+                          -0.7
+                        ],
+                        [
+                          0,
+                          0
+                        ]
+                      ],
+                      "o": [
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          8,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          1.6,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -1.9,
+                          -1.6
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0,
+                          6.4
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -6.4,
+                          0
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          -1,
+                          0.7
+                        ],
+                        [
+                          0,
+                          0
+                        ],
+                        [
+                          0.1,
+                          7.9
+                        ]
+                      ],
+                      "v": [
+                        [
+                          -64,
+                          75.3
+                        ],
+                        [
+                          69.1,
+                          75.3
+                        ],
+                        [
+                          83.6,
+                          60.8
+                        ],
+                        [
+                          83.6,
+                          -81
+                        ],
+                        [
+                          86.5,
+                          -83.9
+                        ],
+                        [
+                          86.5,
+                          -100.9
+                        ],
+                        [
+                          80.7,
+                          -105.6
+                        ],
+                        [
+                          80.7,
+                          60.8
+                        ],
+                        [
+                          69.1,
+                          72.4
+                        ],
+                        [
+                          -64,
+                          72.4
+                        ],
+                        [
+                          -75.6,
+                          60.8
+                        ],
+                        [
+                          -75.6,
+                          -107.3
+                        ],
+                        [
+                          -78.5,
+                          -105.2
+                        ],
+                        [
+                          -78.5,
+                          60.9
+                        ]
+                      ],
+                      "c": true
+                    },
+                    "ix": 2
+                  },
+                  "nm": "Path 1",
+                  "mn": "ADBE Vector Shape - Group",
+                  "hd": false
+                },
+                {
+                  "ty": "fl",
+                  "c": {
+                    "a": 0,
+                    "k": [
+                      0.854901969433,
+                      0.86274510622,
+                      0.878431379795,
+                      1
+                    ],
+                    "ix": 4
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 5
+                  },
+                  "r": 1,
+                  "bm": 0,
+                  "nm": "Fill 1",
+                  "mn": "ADBE Vector Graphic - Fill",
+                  "hd": false
+                },
+                {
+                  "ty": "tr",
+                  "p": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 2
+                  },
+                  "a": {
+                    "a": 0,
+                    "k": [
+                      0,
+                      0
+                    ],
+                    "ix": 1
+                  },
+                  "s": {
+                    "a": 0,
+                    "k": [
+                      100,
+                      100
+                    ],
+                    "ix": 3
+                  },
+                  "r": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 6
+                  },
+                  "o": {
+                    "a": 0,
+                    "k": 100,
+                    "ix": 7
+                  },
+                  "sk": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 4
+                  },
+                  "sa": {
+                    "a": 0,
+                    "k": 0,
+                    "ix": 5
+                  },
+                  "nm": "Transform"
+                }
+              ],
+              "nm": "Group 1",
+              "np": 2,
+              "cix": 2,
+              "bm": 0,
+              "ix": 1,
+              "mn": "ADBE Vector Group",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Group 1",
+          "np": 1,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 0,
+      "op": 300,
+      "st": 0,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 3,
+      "ty": 4,
+      "nm": "cursor 5",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 36,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 39.582,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 44.953,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 55.697265625,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            207.641,
+            154.48,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -180.5,
+            -165.5,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0,
+                  0,
+                  0
+                ],
+                "y": [
+                  1,
+                  1,
+                  1
+                ]
+              },
+              "o": {
+                "x": [
+                  0.45,
+                  0.45,
+                  0.45
+                ],
+                "y": [
+                  0,
+                  0,
+                  0
+                ]
+              },
+              "t": 37.791,
+              "s": [
+                27.252,
+                27.252,
+                100
+              ]
+            },
+            {
+              "t": 59,
+              "s": [
+                56.661,
+                56.661,
+                100
+              ]
+            }
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "d": 1,
+              "ty": "el",
+              "s": {
+                "a": 0,
+                "k": [
+                  63.109,
+                  63.109
+                ],
+                "ix": 2
+              },
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 3
+              },
+              "nm": "Ellipse Path 1",
+              "mn": "ADBE Vector Shape - Ellipse",
+              "hd": false
+            },
+            {
+              "ty": "st",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.182245725744,
+                  0.894323072246,
+                  1
+                ],
+                "ix": 3
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "w": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "lc": 1,
+              "lj": 1,
+              "ml": 4,
+              "bm": 0,
+              "nm": "Stroke 1",
+              "mn": "ADBE Vector Graphic - Stroke",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.522196631338,
+                  0.9762855081,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 50,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  -180.5,
+                  -165.5
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Ellipse 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 36,
+      "op": 59,
+      "st": -1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 4,
+      "ty": 4,
+      "nm": "cursor 4",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 22,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 25.58,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 30.953,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 41.697265625,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            207.641,
+            154.48,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -180.5,
+            -165.5,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0,
+                  0,
+                  0
+                ],
+                "y": [
+                  1,
+                  1,
+                  1
+                ]
+              },
+              "o": {
+                "x": [
+                  0.45,
+                  0.45,
+                  0.45
+                ],
+                "y": [
+                  0,
+                  0,
+                  0
+                ]
+              },
+              "t": 23.789,
+              "s": [
+                27.252,
+                27.252,
+                100
+              ]
+            },
+            {
+              "t": 45,
+              "s": [
+                56.661,
+                56.661,
+                100
+              ]
+            }
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "d": 1,
+              "ty": "el",
+              "s": {
+                "a": 0,
+                "k": [
+                  63.109,
+                  63.109
+                ],
+                "ix": 2
+              },
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 3
+              },
+              "nm": "Ellipse Path 1",
+              "mn": "ADBE Vector Shape - Ellipse",
+              "hd": false
+            },
+            {
+              "ty": "st",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.182245725744,
+                  0.894323072246,
+                  1
+                ],
+                "ix": 3
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "w": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "lc": 1,
+              "lj": 1,
+              "ml": 4,
+              "bm": 0,
+              "nm": "Stroke 1",
+              "mn": "ADBE Vector Graphic - Stroke",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.522196631338,
+                  0.9762855081,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 50,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  -180.5,
+                  -165.5
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Ellipse 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 22,
+      "op": 45,
+      "st": -3,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 5,
+      "ty": 4,
+      "nm": "cursor",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 8,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 11.582,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 16.953,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 27.697265625,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            207.641,
+            154.48,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -180.5,
+            -165.5,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0,
+                  0,
+                  0
+                ],
+                "y": [
+                  1,
+                  1,
+                  1
+                ]
+              },
+              "o": {
+                "x": [
+                  0.45,
+                  0.45,
+                  0.45
+                ],
+                "y": [
+                  0,
+                  0,
+                  0
+                ]
+              },
+              "t": 9.791,
+              "s": [
+                27.252,
+                27.252,
+                100
+              ]
+            },
+            {
+              "t": 31,
+              "s": [
+                56.661,
+                56.661,
+                100
+              ]
+            }
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "shapes": [
+        {
+          "ty": "gr",
+          "it": [
+            {
+              "d": 1,
+              "ty": "el",
+              "s": {
+                "a": 0,
+                "k": [
+                  63.109,
+                  63.109
+                ],
+                "ix": 2
+              },
+              "p": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 3
+              },
+              "nm": "Ellipse Path 1",
+              "mn": "ADBE Vector Shape - Ellipse",
+              "hd": false
+            },
+            {
+              "ty": "st",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.182245725744,
+                  0.894323072246,
+                  1
+                ],
+                "ix": 3
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "w": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "lc": 1,
+              "lj": 1,
+              "ml": 4,
+              "bm": 0,
+              "nm": "Stroke 1",
+              "mn": "ADBE Vector Graphic - Stroke",
+              "hd": false
+            },
+            {
+              "ty": "fl",
+              "c": {
+                "a": 0,
+                "k": [
+                  1,
+                  0.522196631338,
+                  0.9762855081,
+                  1
+                ],
+                "ix": 4
+              },
+              "o": {
+                "a": 0,
+                "k": 50,
+                "ix": 5
+              },
+              "r": 1,
+              "bm": 0,
+              "nm": "Fill 1",
+              "mn": "ADBE Vector Graphic - Fill",
+              "hd": false
+            },
+            {
+              "ty": "tr",
+              "p": {
+                "a": 0,
+                "k": [
+                  -180.5,
+                  -165.5
+                ],
+                "ix": 2
+              },
+              "a": {
+                "a": 0,
+                "k": [
+                  0,
+                  0
+                ],
+                "ix": 1
+              },
+              "s": {
+                "a": 0,
+                "k": [
+                  100,
+                  100
+                ],
+                "ix": 3
+              },
+              "r": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "o": {
+                "a": 0,
+                "k": 100,
+                "ix": 7
+              },
+              "sk": {
+                "a": 0,
+                "k": 0,
+                "ix": 4
+              },
+              "sa": {
+                "a": 0,
+                "k": 0,
+                "ix": 5
+              },
+              "nm": "Transform"
+            }
+          ],
+          "nm": "Ellipse 1",
+          "np": 3,
+          "cix": 2,
+          "bm": 0,
+          "ix": 1,
+          "mn": "ADBE Vector Group",
+          "hd": false
+        }
+      ],
+      "ip": 8,
+      "op": 31,
+      "st": -5,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 6,
+      "ty": 0,
+      "nm": "BG_White",
+      "refId": "comp_0",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            206,
+            150,
+            0
+          ],
+          "ix": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            206,
+            150,
+            0
+          ],
+          "ix": 1
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6
+        }
+      },
+      "ao": 0,
+      "w": 412,
+      "h": 300,
+      "ip": 0,
+      "op": 1800,
+      "st": 0,
+      "bm": 0
+    }
+  ],
+  "markers": []
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/res/raw/empty.json b/packages/SettingsLib/Spa/tests/res/raw/empty.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/res/raw/empty.json
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt
index d2a07e9..54abec9 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt
@@ -17,12 +17,14 @@
 package com.android.settingslib.spa.widget
 
 import androidx.annotation.DrawableRes
+import androidx.annotation.RawRes
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.semantics.SemanticsPropertyKey
 import androidx.compose.ui.semantics.SemanticsPropertyReceiver
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.test.SemanticsMatcher
 import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.filterToOne
 import androidx.compose.ui.test.hasAnyAncestor
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -54,9 +56,32 @@
         fun hasDrawable(@DrawableRes id: Int): SemanticsMatcher =
             SemanticsMatcher.expectValue(DrawableId, id)
 
-        val isIllustrationNode = !hasAnyAncestor(hasDrawable(resId))
+        val isIllustrationNode = hasAnyAncestor(hasDrawable(resId))
         composeTestRule.onAllNodes(hasDrawable(resId))
             .filterToOne(isIllustrationNode)
             .assertIsDisplayed()
     }
+
+    private val RawId = SemanticsPropertyKey<Int>("RawResId")
+    private var SemanticsPropertyReceiver.rawId by RawId
+
+    @Test
+    fun empty_lottie_not_displayed() {
+        val resId = R.raw.empty
+        composeTestRule.setContent {
+            Illustration(
+                resId = resId,
+                resourceType = ResourceType.LOTTIE,
+                modifier = Modifier.semantics { rawId = resId }
+            )
+        }
+
+        fun hasRaw(@RawRes id: Int): SemanticsMatcher =
+            SemanticsMatcher.expectValue(RawId, id)
+
+        val isIllustrationNode = hasAnyAncestor(hasRaw(resId))
+        composeTestRule.onAllNodes(hasRaw(resId))
+            .filterToOne(isIllustrationNode)
+            .assertIsNotDisplayed()
+    }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 8876f66..93ba4f7 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -24,6 +24,7 @@
 import android.content.pm.ApplicationInfo
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Transformations
 
 class AppOpsController(
     context: Context,
@@ -32,21 +33,23 @@
 ) {
     private val appOpsManager = checkNotNull(context.getSystemService(AppOpsManager::class.java))
 
+    val mode: LiveData<Int>
+        get() = _mode
     val isAllowed: LiveData<Boolean>
-        get() = _isAllowed
+        get() = Transformations.map(_mode) { it == MODE_ALLOWED }
 
     fun setAllowed(allowed: Boolean) {
         val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
         appOpsManager.setMode(op, app.uid, app.packageName, mode)
-        _isAllowed.postValue(allowed)
+        _mode.postValue(mode)
     }
 
     @Mode
     fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)
 
-    private val _isAllowed = object : MutableLiveData<Boolean>() {
+    private val _mode = object : MutableLiveData<Int>() {
         override fun onActive() {
-            postValue(getMode() == MODE_ALLOWED)
+            postValue(getMode())
         }
 
         override fun onInactive() {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
index e521edd..ba8af54 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
@@ -16,31 +16,52 @@
 
 package com.android.settingslib.spaprivileged.model.app
 
+import android.app.AppGlobals
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageInfo
+import android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED
 import android.content.pm.PackageManager
 import android.util.Log
+import com.android.settingslib.spa.framework.util.asyncFilter
 
 private const val TAG = "PackageManagers"
 
 object PackageManagers {
-    fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo =
-        PackageManager.getPackageInfoAsUserCached(packageName, 0, userId)
+    private val iPackageManager by lazy { AppGlobals.getPackageManager() }
+
+    fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo? =
+        getPackageInfoAsUser(packageName, 0, userId)
 
     fun getApplicationInfoAsUser(packageName: String, userId: Int): ApplicationInfo =
         PackageManager.getApplicationInfoAsUserCached(packageName, 0, userId)
 
-    fun hasRequestPermission(app: ApplicationInfo, permission: String): Boolean {
-        val packageInfo = try {
-            PackageManager.getPackageInfoAsUserCached(
-                app.packageName, PackageManager.GET_PERMISSIONS.toLong(), app.userId
-            )
-        } catch (e: PackageManager.NameNotFoundException) {
-            Log.w(TAG, "getPackageInfoAsUserCached() failed", e)
-            return false
-        }
+    fun ApplicationInfo.hasRequestPermission(permission: String): Boolean {
+        val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
         return packageInfo?.requestedPermissions?.let {
             permission in it
         } ?: false
     }
+
+    fun ApplicationInfo.hasGrantPermission(permission: String): Boolean {
+        val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
+            ?: return false
+        val index = packageInfo.requestedPermissions.indexOf(permission)
+        return index >= 0 &&
+            packageInfo.requestedPermissionsFlags[index].hasFlag(REQUESTED_PERMISSION_GRANTED)
+    }
+
+    suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> =
+        iPackageManager.getAppOpPermissionPackages(permission, userId).asIterable().asyncFilter {
+            iPackageManager.isPackageAvailable(it, userId)
+        }.toSet()
+
+    private fun getPackageInfoAsUser(packageName: String, flags: Int, userId: Int): PackageInfo? =
+        try {
+            PackageManager.getPackageInfoAsUserCached(packageName, flags.toLong(), userId)
+        } catch (e: PackageManager.NameNotFoundException) {
+            Log.w(TAG, "getPackageInfoAsUserCached() failed", e)
+            null
+        }
+
+    private fun Int.hasFlag(flag: Int) = (this and flag) > 0
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
new file mode 100644
index 0000000..0615807
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.model.enterprise
+
+import android.app.admin.DevicePolicyResources.Strings.Settings
+import android.content.Context
+import android.os.UserHandle
+import android.os.UserManager
+import androidx.lifecycle.LiveData
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
+import com.android.settingslib.RestrictedLockUtilsInternal
+import com.android.settingslib.spaprivileged.R
+
+data class Restrictions(
+    val userId: Int,
+    val keys: List<String>,
+)
+
+sealed class RestrictedMode
+
+object NoRestricted : RestrictedMode()
+
+object BaseUserRestricted : RestrictedMode()
+
+data class BlockedByAdmin(
+    val enterpriseRepository: EnterpriseRepository,
+    val enforcedAdmin: EnforcedAdmin,
+) : RestrictedMode() {
+    fun getSummary(checked: Boolean?): String = when (checked) {
+        true -> enterpriseRepository.getEnterpriseString(
+            Settings.ENABLED_BY_ADMIN_SWITCH_SUMMARY, R.string.enabled_by_admin
+        )
+        false -> enterpriseRepository.getEnterpriseString(
+            Settings.DISABLED_BY_ADMIN_SWITCH_SUMMARY, R.string.disabled_by_admin
+        )
+        else -> ""
+    }
+}
+
+class RestrictionsProvider(
+    private val context: Context,
+    private val restrictions: Restrictions,
+) {
+    private val userManager by lazy { UserManager.get(context) }
+    private val enterpriseRepository by lazy { EnterpriseRepository(context) }
+
+    val restrictedMode = object : LiveData<RestrictedMode>() {
+        override fun onActive() {
+            postValue(getRestrictedMode())
+        }
+
+        override fun onInactive() {
+        }
+    }
+
+    private fun getRestrictedMode(): RestrictedMode {
+        for (key in restrictions.keys) {
+            if (userManager.hasBaseUserRestriction(key, UserHandle.of(restrictions.userId))) {
+                return BaseUserRestricted
+            }
+        }
+        for (key in restrictions.keys) {
+            RestrictedLockUtilsInternal
+                .checkIfRestrictionEnforced(context, key, restrictions.userId)
+                ?.let {
+                    return BlockedByAdmin(
+                        enterpriseRepository = enterpriseRepository,
+                        enforcedAdmin = it,
+                    )
+                }
+        }
+        return NoRestricted
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
index 99deb70..f51d2db 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
@@ -49,7 +49,8 @@
             ),
         horizontalAlignment = Alignment.CenterHorizontally,
     ) {
-        val packageInfo = remember { PackageManagers.getPackageInfoAsUser(packageName, userId) }
+        val packageInfo =
+            remember { PackageManagers.getPackageInfoAsUser(packageName, userId) } ?: return
         Box(modifier = Modifier.padding(SettingsDimension.itemPaddingAround)) {
             AppIcon(app = packageInfo.applicationInfo, size = SettingsDimension.appIconInfoSize)
         }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index 67fa278..d537ec2 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -44,6 +44,7 @@
 fun <T : AppRecord> AppListPage(
     title: String,
     listModel: AppListModel<T>,
+    primaryUserOnly: Boolean = false,
     appItem: @Composable (itemState: AppListItemModel<T>) -> Unit,
 ) {
     val showSystem = rememberSaveable { mutableStateOf(false) }
@@ -55,7 +56,7 @@
         },
     ) { paddingValues ->
         Spacer(Modifier.padding(paddingValues))
-        WorkProfilePager { userInfo ->
+        WorkProfilePager(primaryUserOnly) { userInfo ->
             Column(Modifier.fillMaxSize()) {
                 val options = remember { listModel.getSpinnerOptions() }
                 val selectedOption = rememberSaveable { mutableStateOf(0) }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
new file mode 100644
index 0000000..c6f41d3
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.app.AppOpsManager.MODE_ALLOWED
+import android.app.AppOpsManager.MODE_DEFAULT
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.remember
+import com.android.settingslib.spaprivileged.model.app.AppOpsController
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.PackageManagers
+import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasGrantPermission
+import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasRequestPermission
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+data class AppOpPermissionRecord(
+    override val app: ApplicationInfo,
+    val hasRequestPermission: Boolean,
+    var appOpsController: AppOpsController,
+) : AppRecord
+
+abstract class AppOpPermissionListModel(private val context: Context) :
+    TogglePermissionAppListModel<AppOpPermissionRecord> {
+
+    abstract val appOp: Int
+    abstract val permission: String
+
+    private val notChangeablePackages =
+        setOf("android", "com.android.systemui", context.packageName)
+
+    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
+        userIdFlow.map { userId ->
+            PackageManagers.getAppOpPermissionPackages(userId, permission)
+        }.combine(appListFlow) { packageNames, appList ->
+            appList.map { app ->
+                AppOpPermissionRecord(
+                    app = app,
+                    hasRequestPermission = app.packageName in packageNames,
+                    appOpsController = AppOpsController(context = context, app = app, op = appOp),
+                )
+            }
+        }
+
+    override fun transformItem(app: ApplicationInfo) = AppOpPermissionRecord(
+        app = app,
+        hasRequestPermission = app.hasRequestPermission(permission),
+        appOpsController = AppOpsController(context = context, app = app, op = appOp),
+    )
+
+    override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<AppOpPermissionRecord>>) =
+        recordListFlow.map { recordList ->
+            recordList.filter { it.hasRequestPermission }
+        }
+
+    /**
+     * Defining the default behavior as permissible as long as the package requested this permission
+     * (This means pre-M gets approval during install time; M apps gets approval during runtime).
+     */
+    @Composable
+    override fun isAllowed(record: AppOpPermissionRecord): State<Boolean?> {
+        val mode = record.appOpsController.mode.observeAsState()
+        return remember {
+            derivedStateOf {
+                when (mode.value) {
+                    null -> null
+                    MODE_ALLOWED -> true
+                    MODE_DEFAULT -> record.app.hasGrantPermission(permission)
+                    else -> false
+                }
+            }
+        }
+    }
+
+    override fun isChangeable(record: AppOpPermissionRecord) =
+        record.hasRequestPermission && record.app.packageName !in notChangeablePackages
+
+    override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+        record.appOpsController.setAllowed(newAllowed)
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
index d4d8ea4..ae4f8bd 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
@@ -34,11 +34,12 @@
 import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
 import com.android.settingslib.spa.framework.compose.navigator
-import com.android.settingslib.spa.widget.preference.SwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
 import com.android.settingslib.spaprivileged.model.app.toRoute
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
 import kotlinx.coroutines.Dispatchers
 
 private const val ENTRY_NAME = "AllowControl"
@@ -82,7 +83,7 @@
         internal fun navigator(permissionType: String, app: ApplicationInfo) =
             navigator(route = "$PAGE_NAME/$permissionType/${app.toRoute()}")
 
-        internal fun buildPageId(permissionType: String): SettingsPage {
+        internal fun buildPageData(permissionType: String): SettingsPage {
             return SettingsPage.create(
                 PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
         }
@@ -105,7 +106,7 @@
         LaunchedEffect(model, Dispatchers.Default) {
             model.initState()
         }
-        SwitchPreference(model)
+        RestrictedSwitchPreference(model, Restrictions(userId, listModel.switchRestrictionKeys))
     }
 }
 
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
index 4c748b8..74a50de 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
@@ -37,6 +37,8 @@
     val pageTitleResId: Int
     val switchTitleResId: Int
     val footerResId: Int
+    val switchRestrictionKeys: List<String>
+        get() = emptyList()
 
     /**
      * Loads the extra info for the App List, and generates the [AppRecord] List.
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
index f91a34a..475e930 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
@@ -22,6 +22,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
@@ -37,6 +38,10 @@
 import com.android.settingslib.spaprivileged.R
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.userId
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
 import kotlinx.coroutines.flow.Flow
 
 private const val ENTRY_NAME = "AppList"
@@ -56,7 +61,7 @@
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
         val permissionType = parameter.getStringArg(PERMISSION, arguments)!!
         val appListPage = SettingsPage.create(name, parameter, arguments)
-        val appInfoPage = TogglePermissionAppInfoPageProvider.buildPageId(permissionType)
+        val appInfoPage = TogglePermissionAppInfoPageProvider.buildPageData(permissionType)
         val entryList = mutableListOf<SettingsEntry>()
         // TODO: add more categories, such as personal, work, cloned, etc.
         for (category in listOf("personal")) {
@@ -110,7 +115,7 @@
         internal fun buildInjectEntry(permissionType: String): SettingsEntryBuilder {
             val appListPage = SettingsPage.create(
                 PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
-            return SettingsEntryBuilder.createInject(appListPage).setIsAllowSearch(false)
+            return SettingsEntryBuilder.createInject(owner = appListPage).setIsAllowSearch(false)
         }
     }
 }
@@ -127,15 +132,32 @@
 
     @Composable
     override fun getSummary(option: Int, record: T): State<String> {
+        val restrictionsProvider = remember {
+            val restrictions = Restrictions(
+                userId = record.app.userId,
+                keys = listModel.switchRestrictionKeys,
+            )
+            RestrictionsProvider(context, restrictions)
+        }
+        val restrictedMode = restrictionsProvider.restrictedMode.observeAsState()
         val allowed = listModel.isAllowed(record)
         return remember {
             derivedStateOf {
-                when (allowed.value) {
-                    true -> context.getString(R.string.app_permission_summary_allowed)
-                    false -> context.getString(R.string.app_permission_summary_not_allowed)
-                    else -> ""
-                }
+                RestrictedSwitchPreference.getSummary(
+                    context = context,
+                    restrictedMode = restrictedMode.value,
+                    noRestrictedSummary = getNoRestrictedSummary(allowed),
+                    checked = allowed,
+                ).value
             }
         }
     }
+
+    private fun getNoRestrictedSummary(allowed: State<Boolean?>) = derivedStateOf {
+        when (allowed.value) {
+            true -> context.getString(R.string.app_permission_summary_allowed)
+            false -> context.getString(R.string.app_permission_summary_not_allowed)
+            else -> context.getString(R.string.summary_placeholder)
+        }
+    }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt
index aa5ccf1..a76c438 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/common/WorkProfilePager.kt
@@ -26,11 +26,16 @@
 import com.android.settingslib.spaprivileged.model.enterprise.EnterpriseRepository
 
 @Composable
-fun WorkProfilePager(content: @Composable (userInfo: UserInfo) -> Unit) {
+fun WorkProfilePager(
+    primaryUserOnly: Boolean = false,
+    content: @Composable (userInfo: UserInfo) -> Unit,
+) {
     val context = LocalContext.current
     val profiles = remember {
         val userManager = checkNotNull(context.getSystemService(UserManager::class.java))
-        userManager.getProfiles(UserHandle.myUserId())
+        userManager.getProfiles(UserHandle.myUserId()).filter { userInfo ->
+            !primaryUserOnly || userInfo.isPrimary
+        }
     }
     val titles = remember {
         val enterpriseRepository = EnterpriseRepository(context)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
new file mode 100644
index 0000000..31fd3ad
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.preference
+
+import android.content.Context
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.semantics.Role
+import com.android.settingslib.RestrictedLockUtils
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.preference.SwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
+import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+
+@Composable
+fun RestrictedSwitchPreference(model: SwitchPreferenceModel, restrictions: Restrictions) {
+    if (restrictions.keys.isEmpty()) {
+        SwitchPreference(model)
+        return
+    }
+    val context = LocalContext.current
+    val restrictionsProvider = remember { RestrictionsProvider(context, restrictions) }
+    val restrictedMode = restrictionsProvider.restrictedMode.observeAsState().value ?: return
+    val restrictedSwitchModel = remember(restrictedMode) {
+        RestrictedSwitchPreferenceModel(context, model, restrictedMode)
+    }
+    Box(remember { restrictedSwitchModel.getModifier() }) {
+        SwitchPreference(restrictedSwitchModel)
+    }
+}
+
+object RestrictedSwitchPreference {
+    fun getSummary(
+        context: Context,
+        restrictedMode: RestrictedMode?,
+        noRestrictedSummary: State<String>,
+        checked: State<Boolean?>,
+    ): State<String> = when (restrictedMode) {
+        is NoRestricted -> noRestrictedSummary
+        is BaseUserRestricted -> stateOf(context.getString(R.string.disabled))
+        is BlockedByAdmin -> derivedStateOf { restrictedMode.getSummary(checked.value) }
+        null -> stateOf(context.getString(R.string.summary_placeholder))
+    }
+}
+
+private class RestrictedSwitchPreferenceModel(
+    private val context: Context,
+    model: SwitchPreferenceModel,
+    private val restrictedMode: RestrictedMode,
+) : SwitchPreferenceModel {
+    override val title = model.title
+
+    override val summary = RestrictedSwitchPreference.getSummary(
+        context = context,
+        restrictedMode = restrictedMode,
+        noRestrictedSummary = model.summary,
+        checked = model.checked,
+    )
+
+    override val checked = when (restrictedMode) {
+        is NoRestricted -> model.checked
+        is BaseUserRestricted -> stateOf(false)
+        is BlockedByAdmin -> model.checked
+    }
+
+    override val changeable = when (restrictedMode) {
+        is NoRestricted -> model.changeable
+        is BaseUserRestricted -> stateOf(false)
+        is BlockedByAdmin -> stateOf(false)
+    }
+
+    override val onCheckedChange = when (restrictedMode) {
+        is NoRestricted -> model.onCheckedChange
+        is BaseUserRestricted -> null
+        is BlockedByAdmin -> null
+    }
+
+    fun getModifier(): Modifier = when (restrictedMode) {
+        is BlockedByAdmin -> Modifier.clickable(role = Role.Switch) {
+            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
+                context, restrictedMode.enforcedAdmin
+            )
+        }
+        else -> Modifier
+    }
+}
diff --git a/packages/SettingsLib/TopIntroPreference/Android.bp b/packages/SettingsLib/TopIntroPreference/Android.bp
index ecf2a72..9e86567 100644
--- a/packages/SettingsLib/TopIntroPreference/Android.bp
+++ b/packages/SettingsLib/TopIntroPreference/Android.bp
@@ -23,5 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.cellbroadcast",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp
index 1b00261..dc88304 100644
--- a/packages/SettingsLib/Utils/Android.bp
+++ b/packages/SettingsLib/Utils/Android.bp
@@ -26,5 +26,6 @@
         "com.android.adservices",
         "com.android.permission",
         "com.android.cellbroadcast",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
deleted file mode 100644
index c8a80ac..0000000
--- a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="0.24" android:color="?android:attr/colorBackground" />
-</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
deleted file mode 100644
index 8dcfdbb..0000000
--- a/packages/SettingsLib/res/color/dark_mode_icon_color_dual_tone_fill.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="0.47" android:color="?android:attr/colorBackground" />
-</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
deleted file mode 100644
index 34de548..0000000
--- a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="0.3" android:color="?android:attr/colorForeground" />
-</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml b/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
deleted file mode 100644
index 15944c3..0000000
--- a/packages/SettingsLib/res/color/light_mode_icon_color_dual_tone_fill.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?android:attr/colorForeground" />
-</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_5g_uc_mobiledata.xml b/packages/SettingsLib/res/drawable/ic_5g_uc_mobiledata.xml
deleted file mode 100644
index 93fcad2..0000000
--- a/packages/SettingsLib/res/drawable/ic_5g_uc_mobiledata.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-     Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="27dp"
-        android:height="16dp"
-        android:viewportWidth="27.0"
-        android:viewportHeight="16.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M5.3,13.22c-0.57,0 -1.1,-0.11 -1.58,-0.34c-0.48,-0.22 -0.87,-0.55 -1.18,-0.98C2.24,11.47 2.06,10.93 2,10.3l1.48,-0.2c0.07,0.5 0.25,0.92 0.56,1.25c0.32,0.32 0.74,0.48 1.26,0.48c0.57,0 1.02,-0.18 1.34,-0.55c0.33,-0.37 0.49,-0.87 0.49,-1.48c0,-0.61 -0.16,-1.09 -0.49,-1.46C6.32,7.96 5.88,7.78 5.32,7.78C5,7.78 4.7,7.85 4.42,8C4.15,8.14 3.93,8.33 3.76,8.56L2.28,7.92l0.6,-4.94h5.26v1.36H4.1L3.72,7.02l0.08,0.03C4,6.87 4.25,6.73 4.55,6.62c0.3,-0.12 0.63,-0.18 1.01,-0.18c0.6,0 1.13,0.14 1.6,0.41C7.62,7.11 7.98,7.5 8.24,8c0.27,0.5 0.41,1.1 0.41,1.79c0,0.66 -0.14,1.26 -0.43,1.78c-0.28,0.51 -0.67,0.92 -1.18,1.22C6.55,13.08 5.97,13.22 5.3,13.22z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M14.51,13.22c-0.88,0 -1.66,-0.21 -2.34,-0.64c-0.67,-0.44 -1.2,-1.05 -1.6,-1.83C10.19,9.95 10,9.03 10,7.99c0,-1.05 0.21,-1.96 0.62,-2.74c0.41,-0.79 0.97,-1.4 1.67,-1.83c0.7,-0.44 1.5,-0.66 2.39,-0.66c1.09,0 2.01,0.25 2.74,0.76c0.75,0.5 1.22,1.21 1.41,2.11l-1.47,0.39c-0.17,-0.56 -0.48,-1 -0.94,-1.32c-0.45,-0.33 -1.03,-0.49 -1.75,-0.49c-0.57,0 -1.09,0.14 -1.57,0.43c-0.48,0.29 -0.85,0.71 -1.13,1.27s-0.42,1.25 -0.42,2.07c0,0.81 0.14,1.5 0.41,2.07c0.28,0.56 0.65,0.98 1.11,1.27c0.47,0.29 0.98,0.43 1.54,0.43c0.57,0 1.06,-0.11 1.47,-0.34c0.42,-0.23 0.75,-0.55 0.99,-0.94c0.25,-0.4 0.41,-0.85 0.46,-1.36h-2.88V7.79h4.37c0,0.87 0,1.74 0,2.6c0,0.87 0,1.74 0,2.6H17.6v-1.4h-0.08c-0.28,0.49 -0.67,0.88 -1.18,1.18C15.85,13.07 15.24,13.22 14.51,13.22z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M23,7.39c-0.53,0 -0.94,-0.16 -1.25,-0.47C21.45,6.6 21.3,6.16 21.3,5.6V3h0.8v2.66c0,0.3 0.08,0.54 0.23,0.71C22.48,6.54 22.7,6.62 23,6.62c0.3,0 0.52,-0.08 0.67,-0.25c0.15,-0.17 0.23,-0.41 0.23,-0.71V3h0.8v2.6c0,0.36 -0.07,0.67 -0.2,0.94s-0.33,0.48 -0.58,0.62C23.65,7.32 23.35,7.39 23,7.39z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M22.99,13.1c-0.39,0 -0.73,-0.09 -1.03,-0.28c-0.3,-0.19 -0.53,-0.45 -0.7,-0.79C21.08,11.7 21,11.3 21,10.85c0,-0.46 0.08,-0.85 0.25,-1.19c0.17,-0.34 0.41,-0.6 0.71,-0.78c0.3,-0.18 0.65,-0.28 1.04,-0.28c0.31,0 0.59,0.05 0.86,0.16c0.26,0.11 0.48,0.27 0.65,0.48c0.18,0.21 0.28,0.48 0.32,0.8l-0.83,0.14c-0.06,-0.26 -0.17,-0.46 -0.35,-0.6C23.49,9.44 23.27,9.37 23,9.37c-0.22,0 -0.42,0.06 -0.61,0.17c-0.18,0.11 -0.32,0.28 -0.43,0.5c-0.1,0.22 -0.16,0.49 -0.16,0.81c0,0.32 0.05,0.58 0.16,0.8s0.25,0.39 0.43,0.5c0.18,0.11 0.38,0.17 0.61,0.17c0.26,0 0.47,-0.07 0.65,-0.21c0.18,-0.14 0.3,-0.34 0.35,-0.59l0.85,0.09c-0.06,0.29 -0.17,0.54 -0.32,0.77c-0.15,0.22 -0.36,0.39 -0.61,0.52C23.66,13.03 23.35,13.1 22.99,13.1z"/>
-</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_5g_uw_mobiledata.xml b/packages/SettingsLib/res/drawable/ic_5g_uw_mobiledata.xml
deleted file mode 100644
index ca47b6f..0000000
--- a/packages/SettingsLib/res/drawable/ic_5g_uw_mobiledata.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-     Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="27dp"
-        android:height="16dp"
-        android:viewportWidth="27.0"
-        android:viewportHeight="16.0">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M5.3,13.22c-0.57,0 -1.1,-0.11 -1.58,-0.34c-0.48,-0.22 -0.87,-0.55 -1.18,-0.98C2.24,11.47 2.06,10.93 2,10.3l1.48,-0.2c0.07,0.5 0.25,0.92 0.56,1.25c0.32,0.32 0.74,0.48 1.26,0.48c0.57,0 1.02,-0.18 1.34,-0.55c0.33,-0.37 0.49,-0.87 0.49,-1.48c0,-0.61 -0.16,-1.09 -0.49,-1.46C6.32,7.96 5.88,7.78 5.32,7.78C5,7.78 4.7,7.85 4.42,8C4.15,8.14 3.93,8.33 3.76,8.56L2.28,7.92l0.6,-4.94h5.26v1.36H4.1L3.72,7.02l0.08,0.03C4,6.87 4.25,6.73 4.55,6.62c0.3,-0.12 0.63,-0.18 1.01,-0.18c0.6,0 1.13,0.14 1.6,0.41C7.62,7.11 7.98,7.5 8.24,8c0.27,0.5 0.41,1.1 0.41,1.79c0,0.66 -0.14,1.26 -0.43,1.78c-0.28,0.51 -0.67,0.92 -1.18,1.22C6.55,13.08 5.97,13.22 5.3,13.22z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M14.51,13.22c-0.88,0 -1.66,-0.21 -2.34,-0.64c-0.67,-0.44 -1.2,-1.05 -1.6,-1.83C10.19,9.95 10,9.03 10,7.99c0,-1.05 0.21,-1.96 0.62,-2.74c0.41,-0.79 0.97,-1.4 1.67,-1.83c0.7,-0.44 1.5,-0.66 2.39,-0.66c1.09,0 2.01,0.25 2.74,0.76c0.75,0.5 1.22,1.21 1.41,2.11l-1.47,0.39c-0.17,-0.56 -0.48,-1 -0.94,-1.32c-0.45,-0.33 -1.03,-0.49 -1.75,-0.49c-0.57,0 -1.09,0.14 -1.57,0.43c-0.48,0.29 -0.85,0.71 -1.13,1.27s-0.42,1.25 -0.42,2.07c0,0.81 0.14,1.5 0.41,2.07c0.28,0.56 0.65,0.98 1.11,1.27c0.47,0.29 0.98,0.43 1.54,0.43c0.57,0 1.06,-0.11 1.47,-0.34c0.42,-0.23 0.75,-0.55 0.99,-0.94c0.25,-0.4 0.41,-0.85 0.46,-1.36h-2.88V7.79h4.37c0,0.87 0,1.74 0,2.6c0,0.87 0,1.74 0,2.6H17.6v-1.4h-0.08c-0.28,0.49 -0.67,0.88 -1.18,1.18C15.85,13.07 15.24,13.22 14.51,13.22z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M23,7.39c-0.53,0 -0.94,-0.16 -1.25,-0.47C21.45,6.6 21.3,6.16 21.3,5.6V3h0.8v2.66c0,0.3 0.08,0.54 0.23,0.71C22.48,6.54 22.7,6.62 23,6.62c0.3,0 0.52,-0.08 0.67,-0.25c0.15,-0.17 0.23,-0.41 0.23,-0.71V3h0.8v2.6c0,0.36 -0.07,0.67 -0.2,0.94s-0.33,0.48 -0.58,0.62C23.65,7.32 23.35,7.39 23,7.39z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M21.41,13L20.3,8.7h0.73l0.64,2.78l0.07,0.38h0.04l0.09,-0.38l0.81,-2.78h0.66l0.79,2.78l0.09,0.37h0.04l0.07,-0.37l0.65,-2.78h0.72L24.59,13H23.9l-0.78,-2.84l-0.1,-0.41h-0.04l-0.1,0.41L22.08,13H21.41z"/>
-</vector>
diff --git a/packages/SettingsLib/res/layout/preference_category_divider.xml b/packages/SettingsLib/res/layout/preference_category_divider.xml
deleted file mode 100644
index 6644eec..0000000
--- a/packages/SettingsLib/res/layout/preference_category_divider.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/two_target_divider"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:gravity="start|center_vertical"
-    android:orientation="horizontal">
-    <View
-        android:layout_height="1dp"
-        android:layout_width="match_parent"
-        android:background="?android:attr/dividerHorizontal" />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml b/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml
deleted file mode 100644
index 5b5d474..0000000
--- a/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2017 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<!-- Similar to preference_category_material_settings.xml, except that this always adds
-     a divider above category. -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-
-    <include layout="@layout/preference_category_divider"/>
-    <include layout="@layout/preference_category_material"/>
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
deleted file mode 100644
index 52d7775..0000000
--- a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center_vertical"
-    android:minHeight="?android:attr/listPreferredItemHeightSmall"
-    android:paddingEnd="16dp"
-    android:paddingStart="16dp">
-
-    <TextView
-        android:id="@+id/text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceListItemSmall"
-        android:textColor="?android:attr/textColorAlertDialogListItem" />
-
-</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/settings_dialog_title.xml b/packages/SettingsLib/res/layout/settings_dialog_title.xml
deleted file mode 100644
index 1e065e0..0000000
--- a/packages/SettingsLib/res/layout/settings_dialog_title.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/settings_title_panel"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:orientation="vertical">
-
-    <LinearLayout
-        android:id="@+id/settings_title_template"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:gravity="center"
-        android:paddingStart="?android:attr/dialogPreferredPadding"
-        android:paddingEnd="?android:attr/dialogPreferredPadding"
-        android:paddingTop="@*android:dimen/dialog_padding_top_material">
-
-        <ImageView
-            android:id="@+id/settings_icon"
-            android:layout_width="24dip"
-            android:layout_height="24dip"
-            android:layout_marginBottom="12dip" />
-
-        <TextView
-            android:id="@+id/settings_title"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAlignment="center"
-            style="?android:attr/windowTitleStyle" />
-    </LinearLayout>
-
-    <Space
-        android:id="@+id/settings_title_divider"
-        android:visibility="gone"
-        android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/dialog_title_divider_material" />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index d8ed7ed..5b3aae3 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -597,7 +597,7 @@
     <string name="guest_reset_guest" msgid="6110013010356013758">"கெஸ்ட் அமர்வை மீட்டமை"</string>
     <string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"கெஸ்ட்டை மீட்டமைக்கவா?"</string>
     <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"கெஸ்ட் பயனரை அகற்றவா?"</string>
-    <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"மீட்டமை"</string>
+    <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ரீசெட்"</string>
     <string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"அகற்று"</string>
     <string name="guest_resetting" msgid="7822120170191509566">"கெஸ்ட்டை மீட்டமைக்கிறது…"</string>
     <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"கெஸ்ட் அமர்வை ரீசெட் செய்யவா?"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 663e8e4..179573b 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -158,18 +158,6 @@
         <item>Opus</item>
     </string-array>
 
-    <!-- Values for Bluetooth Audio Codec selection preference. -->
-    <string-array name="bluetooth_a2dp_codec_values" translatable="false" >
-        <item>1000000</item>
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-        <item>6</item>
-    </string-array>
-
     <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
     <string-array name="bluetooth_a2dp_codec_summaries" >
         <item>Use System Selection (Default)</item>
@@ -191,15 +179,6 @@
         <item>96.0 kHz</item>
     </string-array>
 
-    <!-- Values for Bluetooth Audio Codec Sample Rate selection preference. -->
-    <string-array name="bluetooth_a2dp_codec_sample_rate_values" translatable="false" >
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-        <item>4</item>
-        <item>8</item>
-    </string-array>
-
     <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50]-->
     <string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
         <item>Use System Selection (Default)</item>
@@ -217,14 +196,6 @@
         <item>32 bits/sample</item>
     </string-array>
 
-    <!-- Values for Bluetooth Audio Codec Bits Per Sample selection preference. -->
-    <string-array name="bluetooth_a2dp_codec_bits_per_sample_values" translatable="false" >
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-        <item>4</item>
-    </string-array>
-
     <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=50]-->
     <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
         <item>Use System Selection (Default)</item>
@@ -240,13 +211,6 @@
         <item>Stereo</item>
     </string-array>
 
-    <!-- Values for Bluetooth Audio Codec Channel Mode selection preference. -->
-    <string-array name="bluetooth_a2dp_codec_channel_mode_values" translatable="false" >
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-    </string-array>
-
     <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=50]-->
     <string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
         <item>Use System Selection (Default)</item>
@@ -262,14 +226,6 @@
         <item>Best Effort (Adaptive Bit Rate)</item>
     </string-array>
 
-    <!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
-    <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_values" translatable="false" >
-        <item>1000</item>
-        <item>1001</item>
-        <item>1002</item>
-        <item>1003</item>
-    </string-array>
-
     <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70]-->
     <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
         <item>Optimized for Audio Quality</item>
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index d2d7471..6b7e918 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -17,9 +17,6 @@
 <resources>
     <color name="disabled_text_color">#66000000</color> <!-- 38% black -->
 
-    <color name="usage_graph_dots">@*android:color/tertiary_device_default_settings</color>
-    <color name="list_divider_color">#64000000</color>
-
     <color name="bt_color_icon_1">#b4a50e0e</color> <!-- 72% Material Red 900 -->
     <color name="bt_color_icon_2">#b40d652d</color> <!-- 72% Material Green 900 -->
     <color name="bt_color_icon_3">#b4e37400</color> <!-- 72% Material Yellow 900 -->
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 226b119..3ef3d36 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -19,16 +19,11 @@
     <!-- The y translation to apply at the start in appear animations. -->
     <dimen name="appear_y_translation_start">32dp</dimen>
 
-    <!-- The translation for disappearing security views after having solved them. -->
-    <dimen name="disappear_y_translation">-32dp</dimen>
-
     <!-- Height of a user icon view -->
     <dimen name="user_icon_view_height">24dp</dimen>
     <!-- User spinner -->
-    <dimen name="user_spinner_height">72dp</dimen>
     <dimen name="user_spinner_padding">4dp</dimen>
     <dimen name="user_spinner_padding_sides">20dp</dimen>
-    <dimen name="user_spinner_item_height">56dp</dimen>
 
     <!-- Lock icon for preferences locked by admin -->
     <dimen name="restricted_icon_padding">4dp</dimen>
@@ -36,10 +31,8 @@
     <dimen name="wifi_preference_badge_padding">8dip</dimen>
 
     <!-- Usage graph dimens -->
-    <dimen name="usage_graph_area_height">122dp</dimen>
     <dimen name="usage_graph_margin_top_bottom">9dp</dimen>
     <dimen name="usage_graph_labels_width">56dp</dimen>
-    <dimen name="usage_graph_labels_padding">16dp</dimen>
 
     <dimen name="usage_graph_divider_size">1dp</dimen>
 
@@ -64,22 +57,13 @@
     <!-- Ratio between width and height -->
     <fraction name="bt_battery_ratio_fraction">35%</fraction>
 
-    <!-- Ratio of height between battery icon and bluetooth icon -->
-    <fraction name="bt_battery_scale_fraction">75%</fraction>
-
     <!-- Fraction value to smooth the edges of the battery icon. The path will be inset by this
          fraction of a pixel.-->
     <fraction name="battery_subpixel_smoothing_left">0%</fraction>
     <fraction name="battery_subpixel_smoothing_right">0%</fraction>
 
-    <!-- Zen mode panel: condition item button padding -->
-    <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen>
-    <!-- Zen mode panel: spacing between condition items -->
-    <dimen name="zen_mode_condition_detail_item_spacing">12dp</dimen>
     <!-- Zen mode panel: spacing between two-line condition upper and lower lines -->
     <dimen name="zen_mode_condition_detail_item_interline_spacing">4dp</dimen>
-    <!-- Zen mode panel: bottom padding, a bit less than qs_panel_padding -->
-    <dimen name="zen_mode_condition_detail_bottom_padding">4dp</dimen>
 
     <!-- SignalDrawable -->
     <dimen name="signal_icon_size">15dp</dimen>
@@ -93,9 +77,6 @@
     <!-- Size of advanced icon -->
     <dimen name="advanced_icon_size">18dp</dimen>
 
-    <!-- Minimum width for the popup for updating a user's photo. -->
-    <dimen name="update_user_photo_popup_min_width">300dp</dimen>
-
     <dimen name="add_a_photo_circled_padding">6dp</dimen>
     <dimen name="user_photo_size_in_user_info_dialog">112dp</dimen>
     <dimen name="add_a_photo_icon_size_in_user_info_dialog">32dp</dimen>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 06d7bb4..2e0155b 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -91,10 +91,6 @@
     <string name="wifi_disabled_generic">Disabled</string>
     <!-- Status for networked disabled from a DNS or DHCP failure -->
     <string name="wifi_disabled_network_failure">IP Configuration Failure</string>
-    <!-- Status for networks disabled by the network recommendation provider -->
-    <string name="wifi_disabled_by_recommendation_provider">Not connected due to low quality network</string>
-    <!-- Status for networked disabled from a wifi association failure -->
-    <string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
     <!-- Status for networks disabled from authentication failure (wrong password
          or certificate). -->
     <string name="wifi_disabled_password_failure">Authentication problem</string>
@@ -114,20 +110,14 @@
     <string name="wifi_no_internet">No internet access</string>
     <!-- Summary for saved networks -->
     <string name="saved_network">Saved by <xliff:g id="name">%1$s</xliff:g></string>
-    <!-- Summary for connect to metered access point [CHAR LIMIT=NONE] -->
-    <string name="connected_to_metered_access_point">Connected to metered network</string>
 
 
     <!-- Status message of Wi-Fi when it is automatically connected by a network recommendation provider. [CHAR LIMIT=NONE] -->
     <string name="connected_via_network_scorer">Automatically connected via %1$s</string>
     <!-- Status message of Wi-Fi when it is automatically connected by a default network recommendation provider. [CHAR LIMIT=NONE] -->
     <string name="connected_via_network_scorer_default">Automatically connected via network rating provider</string>
-    <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
-    <string name="connected_via_passpoint">Connected via %1$s</string>
     <!-- Status message of Wi-Fi when it is connected by a app (via suggestion or network request). [CHAR LIMIT=NONE] -->
     <string name="connected_via_app">Connected via <xliff:g id="name" example="Wifi App">%1$s</xliff:g></string>
-    <!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
-    <string name="available_via_passpoint">Available via %1$s</string>
     <!-- Status message of OSU Provider network when not connected. [CHAR LIMIT=NONE] -->
     <string name="tap_to_sign_up">Tap to sign up</string>
     <!-- Package name for Settings app-->
@@ -153,11 +143,6 @@
     <!-- Summary for networks failing to connect due to association rejection status 17, AP full -->
     <string name="wifi_ap_unable_to_handle_new_sta">Access point temporarily full</string>
 
-    <!-- Status message of Wi-Fi when it is connected to a Carrier Network. [CHAR LIMIT=NONE] -->
-    <string name="connected_via_carrier">Connected via %1$s</string>
-    <!-- Status message of Wi-Fi when an available network is a carrier network. [CHAR LIMIT=NONE] -->
-    <string name="available_via_carrier">Available via %1$s</string>
-
     <!-- Status message of OSU Provider upon initiating provisioning flow [CHAR LIMIT=NONE] -->
     <string name="osu_opening_provider">Opening <xliff:g id="passpointProvider" example="Passpoint Provider">%1$s</xliff:g></string>
     <!-- Status message of OSU Provider when connection fails [CHAR LIMIT=NONE] -->
@@ -169,14 +154,10 @@
     <!-- Status message of OSU Provider on completing provisioning. [CHAR LIMIT=NONE] -->
     <string name="osu_sign_up_complete">Sign-up complete. Connecting\u2026</string>
 
-    <!-- Speed label for very slow network speed -->
-    <string name="speed_label_very_slow">Very Slow</string>
     <!-- Speed label for slow network speed -->
     <string name="speed_label_slow">Slow</string>
     <!-- Speed label for okay network speed -->
     <string name="speed_label_okay">OK</string>
-    <!-- Speed label for medium network speed -->
-    <string name="speed_label_medium">Medium</string>
     <!-- Speed label for fast network speed -->
     <string name="speed_label_fast">Fast</string>
     <!-- Speed label for very fast network speed -->
@@ -203,8 +184,6 @@
     <string name="bluetooth_connected_no_headset">Connected (no phone)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for media audio. [CHAR LIMIT=40] -->
     <string name="bluetooth_connected_no_a2dp">Connected (no media)<xliff:g id="active_device">%1$s</xliff:g></string>
-    <!-- Bluetooth settings.  Message when connected to a device, except for map. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_map">Connected (no message access)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio. [CHAR LIMIT=40] -->
     <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)<xliff:g id="active_device">%1$s</xliff:g></string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 59735f41..85e8aad 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -183,7 +183,7 @@
         final String currentShortcutServiceId = Settings.Secure.getStringForUser(
                 context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                 userId);
-        if (currentShortcutServiceId != null) {
+        if (!TextUtils.isEmpty(currentShortcutServiceId)) {
             return currentShortcutServiceId;
         }
         return context.getString(R.string.config_defaultAccessibilityService);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 3ca94db..7927c5d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -81,8 +81,10 @@
     private int mDeviceMode;
     private long mHiSyncId;
     private int mGroupId;
+
     // Need this since there is no method for getting RSSI
     short mRssi;
+
     // mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
     // because current sub device is only for HearingAid and its profile is the same.
     private final Collection<LocalBluetoothProfile> mProfiles = new CopyOnWriteArrayList<>();
@@ -398,6 +400,7 @@
     * @param id the group id from the CSIP.
     */
     public void setGroupId(int id) {
+        Log.d(TAG, this.getDevice().getAnonymizedAddress() + " set GroupId " + id);
         mGroupId = id;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 26a2080..5662ce6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -357,8 +357,12 @@
      * {@code false}.
      */
     public synchronized boolean shouldPairByCsip(BluetoothDevice device, int groupId) {
-        if (mOngoingSetMemberPair != null || device.getBondState() != BluetoothDevice.BOND_NONE
+        boolean isOngoingSetMemberPair = mOngoingSetMemberPair != null;
+        int bondState = device.getBondState();
+        if (isOngoingSetMemberPair || bondState != BluetoothDevice.BOND_NONE
                 || !mCsipDeviceManager.isExistedGroupId(groupId)) {
+            Log.d(TAG, "isOngoingSetMemberPair: " + isOngoingSetMemberPair
+                    + " , device.getBondState: " + bondState);
             return false;
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 9b38238..d5de3f0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -102,9 +102,12 @@
     }
 
     private CachedBluetoothDevice getCachedDevice(int groupId) {
+        log("getCachedDevice: groupId: " + groupId);
         for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
             CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
             if (cachedDevice.getGroupId() == groupId) {
+                log("getCachedDevice: found cachedDevice with the groupId: "
+                        + cachedDevice.getDevice().getAnonymizedAddress());
                 return cachedDevice;
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 818f5ca..cf4e1ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -46,16 +46,43 @@
         if (isValidHiSyncId(hiSyncId)) {
             // Once hiSyncId is valid, assign hiSyncId
             newDevice.setHiSyncId(hiSyncId);
+            final int side = getDeviceSide(newDevice.getDevice());
+            final int mode = getDeviceMode(newDevice.getDevice());
+            newDevice.setDeviceSide(side);
+            newDevice.setDeviceMode(mode);
         }
     }
 
     private long getHiSyncId(BluetoothDevice device) {
-        LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
-        HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
-        if (profileProxy != null) {
-            return profileProxy.getHiSyncId(device);
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+        if (profileProxy == null) {
+            return BluetoothHearingAid.HI_SYNC_ID_INVALID;
         }
-        return BluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+        return profileProxy.getHiSyncId(device);
+    }
+
+    private int getDeviceSide(BluetoothDevice device) {
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+        if (profileProxy == null) {
+            Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device side");
+            return HearingAidProfile.DeviceSide.SIDE_INVALID;
+        }
+
+        return profileProxy.getDeviceSide(device);
+    }
+
+    private int getDeviceMode(BluetoothDevice device) {
+        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+        final HearingAidProfile profileProxy = profileManager.getHearingAidProfile();
+        if (profileProxy == null) {
+            Log.w(TAG, "HearingAidProfile is not supported and not ready to fetch device mode");
+            return HearingAidProfile.DeviceMode.MODE_INVALID;
+        }
+
+        return profileProxy.getDeviceMode(device);
     }
 
     boolean setSubDeviceIfNeeded(CachedBluetoothDevice newDevice) {
@@ -98,6 +125,10 @@
                 if (isValidHiSyncId(newHiSyncId)) {
                     cachedDevice.setHiSyncId(newHiSyncId);
                     newSyncIdSet.add(newHiSyncId);
+                    final int side = getDeviceSide(cachedDevice.getDevice());
+                    final int mode = getDeviceMode(cachedDevice.getDevice());
+                    cachedDevice.setDeviceSide(side);
+                    cachedDevice.setDeviceMode(mode);
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
new file mode 100644
index 0000000..feb5e0b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.HashMap;
+
+/** Utils class to report hearing aid metrics to statsd */
+public final class HearingAidStatsLogUtils {
+
+    private static final String TAG = "HearingAidStatsLogUtils";
+    private static final HashMap<String, Integer> sDeviceAddressToBondEntryMap = new HashMap<>();
+
+    /**
+     * Sets the mapping from hearing aid device to the bond entry where this device starts it's
+     * bonding(connecting) process.
+     *
+     * @param bondEntry The entry page id where the bonding process starts
+     * @param device The bonding(connecting) hearing aid device
+     */
+    public static void setBondEntryForDevice(int bondEntry, CachedBluetoothDevice device) {
+        sDeviceAddressToBondEntryMap.put(device.getAddress(), bondEntry);
+    }
+
+    /**
+     * Logs hearing aid device information to westworld, including device mode, device side, and
+     * entry page id where the binding(connecting) process starts.
+     *
+     * Only logs the info once after hearing aid is bonded(connected). Clears the map entry of this
+     * device when logging is completed.
+     *
+     * @param device The bonded(connected) hearing aid device
+     */
+    public static void logHearingAidInfo(CachedBluetoothDevice device) {
+        final String deviceAddress = device.getAddress();
+        if (sDeviceAddressToBondEntryMap.containsKey(deviceAddress)) {
+            final int bondEntry = sDeviceAddressToBondEntryMap.getOrDefault(deviceAddress, -1);
+            final int deviceMode = device.getDeviceMode();
+            final int deviceSide = device.getDeviceSide();
+            FrameworkStatsLog.write(FrameworkStatsLog.HEARING_AID_INFO_REPORTED, deviceMode,
+                    deviceSide, bondEntry);
+
+            sDeviceAddressToBondEntryMap.remove(deviceAddress);
+        } else {
+            Log.w(TAG, "The device address was not found. Hearing aid device info is not logged.");
+        }
+    }
+
+    @VisibleForTesting
+    static HashMap<String, Integer> getDeviceAddressToBondEntryMap() {
+        return sDeviceAddressToBondEntryMap;
+    }
+
+    private HearingAidStatsLogUtils() {}
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 01d581e..123c01b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -26,11 +26,17 @@
 import android.bluetooth.BluetoothLeAudioContentMetadata;
 import android.bluetooth.BluetoothLeBroadcast;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastSubgroup;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.SharedPreferences;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -40,6 +46,7 @@
 
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
@@ -54,19 +61,20 @@
  */
 public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
     private static final String TAG = "LocalBluetoothLeBroadcast";
-    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
     private static final boolean DEBUG = BluetoothUtils.D;
 
     static final String NAME = "LE_AUDIO_BROADCAST";
+    private static final String UNDERLINE = "_";
+    private static final int DEFAULT_CODE_MAX = 9999;
+    private static final int DEFAULT_CODE_MIN = 1000;
     // Order of this profile in device profiles list
     private static final int ORDINAL = 1;
-    private static final String PREF_NAME = "LocalBluetoothLeBroadcast";
-    private static final String PREF_PROGRAM_INFO = "PrefProgramInfo";
-    private static final String PREF_BROADCAST_CODE = "PrefBroadcastCode";
-    private static final String PREF_APP_SOURCE_NAME = "PrefAppSourceName";
-    private static final String UNDERLINE = "_";
-    private static final int DEFAULT_CODE_MIN = 1000;
-    private static final int DEFAULT_CODE_MAX = 9999;
+    private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
+    private static final Uri[] SETTINGS_URIS = new Uri[]{
+            Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO),
+            Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE),
+            Settings.Secure.getUriFor(Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME),
+    };
 
     private BluetoothLeBroadcast mService;
     private BluetoothLeAudioContentMetadata mBluetoothLeAudioContentMetadata;
@@ -78,8 +86,9 @@
     private boolean mIsProfileReady;
     private String mProgramInfo;
     private byte[] mBroadcastCode;
-    private SharedPreferences mSharedPref;
     private Executor mExecutor;
+    private ContentResolver mContentResolver;
+    private ContentObserver mSettingsObserver;
 
     private final ServiceListener mServiceListener = new ServiceListener() {
         @Override
@@ -91,6 +100,11 @@
                 mService = (BluetoothLeBroadcast) proxy;
                 mIsProfileReady = true;
                 registerServiceCallBack(mExecutor, mBroadcastCallback);
+                List<BluetoothLeBroadcastMetadata> metadata = getAllBroadcastMetadata();
+                if (!metadata.isEmpty()) {
+                    updateBroadcastInfoFromBroadcastMetadata(metadata.get(0));
+                }
+                registerContentObserver();
             }
         }
 
@@ -102,6 +116,7 @@
             if(mIsProfileReady) {
                 mIsProfileReady = false;
                 unregisterServiceCallBack(mBroadcastCallback);
+                unregisterContentObserver();
             }
         }
     };
@@ -116,7 +131,7 @@
                                         + broadcastId);
                     }
                     setLatestBroadcastId(broadcastId);
-                    setAppSourceName(mNewAppSourceName);
+                    setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
                 }
 
                 @Override
@@ -160,7 +175,7 @@
                                         + broadcastId);
                     }
                     setLatestBroadcastId(broadcastId);
-                    setAppSourceName(mNewAppSourceName);
+                    setAppSourceName(mNewAppSourceName, /*updateContentResolver=*/ true);
                 }
 
                 @Override
@@ -181,30 +196,27 @@
                 }
             };
 
+    private class BroadcastSettingsObserver extends ContentObserver {
+        BroadcastSettingsObserver(Handler h) {
+            super(h);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            Log.d(TAG, "BroadcastSettingsObserver: onChange");
+            updateBroadcastInfoFromContentProvider();
+        }
+    }
+
     LocalBluetoothLeBroadcast(Context context) {
         mExecutor = Executors.newSingleThreadExecutor();
         BluetoothAdapter.getDefaultAdapter().
                 getProfileProxy(context, mServiceListener, BluetoothProfile.LE_AUDIO_BROADCAST);
         mBuilder = new BluetoothLeAudioContentMetadata.Builder();
-        mSharedPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
-        if (mSharedPref != null) {
-            String programInfo = mSharedPref.getString(PREF_PROGRAM_INFO, "");
-            if (programInfo.isEmpty()) {
-                programInfo = getDefaultValueOfProgramInfo();
-            }
-            setProgramInfo(programInfo);
-
-            String prefBroadcastCode = mSharedPref.getString(PREF_BROADCAST_CODE, "");
-            byte[] broadcastCode;
-            if (prefBroadcastCode.isEmpty()) {
-                broadcastCode = getDefaultValueOfBroadcastCode();
-            } else {
-                broadcastCode = prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
-            }
-            setBroadcastCode(broadcastCode);
-
-            mAppSourceName = mSharedPref.getString(PREF_APP_SOURCE_NAME, "");
-        }
+        mContentResolver = context.getContentResolver();
+        Handler handler = new Handler(Looper.getMainLooper());
+        mSettingsObserver = new BroadcastSettingsObserver(handler);
+        updateBroadcastInfoFromContentProvider();
     }
 
     /**
@@ -217,11 +229,12 @@
             Log.d(TAG, "The BluetoothLeBroadcast is null when starting the broadcast.");
             return;
         }
+        String programInfo = getProgramInfo();
         if (DEBUG) {
             Log.d(TAG,
-                    "startBroadcast: language = " + language + " ,programInfo = " + mProgramInfo);
+                    "startBroadcast: language = " + language + " ,programInfo = " + programInfo);
         }
-        buildContentMetadata(language, mProgramInfo);
+        buildContentMetadata(language, programInfo);
         mService.startBroadcast(mBluetoothLeAudioContentMetadata, mBroadcastCode);
     }
 
@@ -230,21 +243,28 @@
     }
 
     public void setProgramInfo(String programInfo) {
-        if (programInfo == null || programInfo.isEmpty()) {
+        setProgramInfo(programInfo, /*updateContentResolver=*/ true);
+    }
+
+    private void setProgramInfo(String programInfo, boolean updateContentResolver) {
+        if (TextUtils.isEmpty(programInfo)) {
             Log.d(TAG, "setProgramInfo: programInfo is null or empty");
             return;
         }
+        if (mProgramInfo != null && TextUtils.equals(mProgramInfo, programInfo)) {
+            Log.d(TAG, "setProgramInfo: programInfo is not changed");
+            return;
+        }
         Log.d(TAG, "setProgramInfo: " + programInfo);
         mProgramInfo = programInfo;
-
-        if (mSharedPref == null) {
-            Log.d(TAG, "setProgramInfo: sharedPref is null");
-            return;
+        if (updateContentResolver) {
+            if (mContentResolver == null) {
+                Log.d(TAG, "mContentResolver is null");
+                return;
+            }
+            Settings.Secure.putString(mContentResolver,
+                    Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, programInfo);
         }
-        SharedPreferences.Editor editor = mSharedPref.edit();
-        editor.putString(PREF_PROGRAM_INFO, mProgramInfo);
-        editor.apply();
-
     }
 
     public byte[] getBroadcastCode() {
@@ -252,22 +272,31 @@
     }
 
     public void setBroadcastCode(byte[] broadcastCode) {
-        if (broadcastCode == null || broadcastCode.length == 0) {
-            Log.d(TAG, "setBroadcastCode: broadcastCode is null or empty");
+        setBroadcastCode(broadcastCode, /*updateContentResolver=*/ true);
+    }
+
+    private void setBroadcastCode(byte[] broadcastCode, boolean updateContentResolver) {
+        if (broadcastCode == null) {
+            Log.d(TAG, "setBroadcastCode: broadcastCode is null");
+            return;
+        }
+        if (mBroadcastCode != null && Arrays.equals(broadcastCode, mBroadcastCode)) {
+            Log.d(TAG, "setBroadcastCode: broadcastCode is not changed");
             return;
         }
         mBroadcastCode = broadcastCode;
-
-        if (mSharedPref == null) {
-            Log.d(TAG, "setBroadcastCode: sharedPref is null");
-            return;
+        if (updateContentResolver) {
+            if (mContentResolver == null) {
+                Log.d(TAG, "mContentResolver is null");
+                return;
+            }
+            Settings.Secure.putString(mContentResolver, Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
+                    new String(broadcastCode, StandardCharsets.UTF_8));
         }
-        SharedPreferences.Editor editor = mSharedPref.edit();
-        editor.putString(PREF_BROADCAST_CODE, new String(broadcastCode, StandardCharsets.UTF_8));
-        editor.apply();
     }
 
     private void setLatestBroadcastId(int broadcastId) {
+        Log.d(TAG, "setLatestBroadcastId: mBroadcastId is " + broadcastId);
         mBroadcastId = broadcastId;
     }
 
@@ -275,19 +304,24 @@
         return mBroadcastId;
     }
 
-    private void setAppSourceName(String appSourceName) {
+    private void setAppSourceName(String appSourceName, boolean updateContentResolver) {
         if (TextUtils.isEmpty(appSourceName)) {
             appSourceName = "";
         }
-        mAppSourceName = appSourceName;
-        mNewAppSourceName = "";
-        if (mSharedPref == null) {
-            Log.d(TAG, "setBroadcastCode: sharedPref is null");
+        if (mAppSourceName != null && TextUtils.equals(mAppSourceName, appSourceName)) {
+            Log.d(TAG, "setAppSourceName: appSourceName is not changed");
             return;
         }
-        SharedPreferences.Editor editor = mSharedPref.edit();
-        editor.putString(PREF_APP_SOURCE_NAME, appSourceName);
-        editor.apply();
+        mAppSourceName = appSourceName;
+        mNewAppSourceName = "";
+        if (updateContentResolver) {
+            if (mContentResolver == null) {
+                Log.d(TAG, "mContentResolver is null");
+                return;
+            }
+            Settings.Secure.putString(mContentResolver,
+                    Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, mAppSourceName);
+        }
     }
 
     public String getAppSourceName() {
@@ -299,6 +333,7 @@
         if (bluetoothLeBroadcastMetadata != null
                 && bluetoothLeBroadcastMetadata.getBroadcastId() == mBroadcastId) {
             mBluetoothLeBroadcastMetadata = bluetoothLeBroadcastMetadata;
+            updateBroadcastInfoFromBroadcastMetadata(bluetoothLeBroadcastMetadata);
         }
     }
 
@@ -318,6 +353,48 @@
         return mBluetoothLeBroadcastMetadata;
     }
 
+    private void updateBroadcastInfoFromContentProvider() {
+        if (mContentResolver == null) {
+            Log.d(TAG, "updateBroadcastInfoFromContentProvider: mContentResolver is null");
+            return;
+        }
+        String programInfo = Settings.Secure.getString(mContentResolver,
+                Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO);
+        if (programInfo == null) {
+            programInfo = getDefaultValueOfProgramInfo();
+        }
+        setProgramInfo(programInfo, /*updateContentResolver=*/ false);
+
+        String prefBroadcastCode = Settings.Secure.getString(mContentResolver,
+                Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE);
+        byte[] broadcastCode = (prefBroadcastCode == null) ? getDefaultValueOfBroadcastCode()
+                : prefBroadcastCode.getBytes(StandardCharsets.UTF_8);
+        setBroadcastCode(broadcastCode, /*updateContentResolver=*/ false);
+
+        String appSourceName = Settings.Secure.getString(mContentResolver,
+                Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME);
+        setAppSourceName(appSourceName, /*updateContentResolver=*/ false);
+    }
+
+    private void updateBroadcastInfoFromBroadcastMetadata(
+            BluetoothLeBroadcastMetadata bluetoothLeBroadcastMetadata) {
+        if (bluetoothLeBroadcastMetadata == null) {
+            Log.d(TAG, "The bluetoothLeBroadcastMetadata is null");
+            return;
+        }
+        setBroadcastCode(bluetoothLeBroadcastMetadata.getBroadcastCode());
+        setLatestBroadcastId(bluetoothLeBroadcastMetadata.getBroadcastId());
+
+        List<BluetoothLeBroadcastSubgroup> subgroup = bluetoothLeBroadcastMetadata.getSubgroups();
+        if (subgroup == null || subgroup.size() < 1) {
+            Log.d(TAG, "The subgroup is not valid value");
+            return;
+        }
+        BluetoothLeAudioContentMetadata contentMetadata = subgroup.get(0).getContentMetadata();
+        setProgramInfo(contentMetadata.getProgramInfo());
+        setAppSourceName(getAppSourceName(), /*updateContentResolver=*/ true);
+    }
+
     /**
      * Stop the latest LE Broadcast. If the system stopped the LE Broadcast, then the system
      * calls the corresponding callback {@link BluetoothLeBroadcast.Callback}.
@@ -350,12 +427,13 @@
             Log.d(TAG, "The BluetoothLeBroadcast is null when updating the broadcast.");
             return;
         }
+        String programInfo = getProgramInfo();
         if (DEBUG) {
             Log.d(TAG,
-                    "updateBroadcast: language = " + language + " ,programInfo = " + mProgramInfo);
+                    "updateBroadcast: language = " + language + " ,programInfo = " + programInfo);
         }
         mNewAppSourceName = appSourceName;
-        mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(mProgramInfo).build();
+        mBluetoothLeAudioContentMetadata = mBuilder.setProgramInfo(programInfo).build();
         mService.updateBroadcast(mBroadcastId, mBluetoothLeAudioContentMetadata);
     }
 
@@ -517,8 +595,7 @@
         if (DEBUG) {
             Log.d(TAG, "resetCacheInfo:");
         }
-        mNewAppSourceName = "";
-        mAppSourceName = "";
+        setAppSourceName("", /*updateContentResolver=*/ true);
         mBluetoothLeBroadcastMetadata = null;
         mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER;
     }
@@ -528,4 +605,22 @@
         //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
         return randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
     }
+
+    private void registerContentObserver() {
+        if (mContentResolver == null) {
+            Log.d(TAG, "mContentResolver is null");
+            return;
+        }
+        for (Uri uri : SETTINGS_URIS) {
+            mContentResolver.registerContentObserver(uri, false, mSettingsObserver);
+        }
+    }
+
+    private void unregisterContentObserver() {
+        if (mContentResolver == null) {
+            Log.d(TAG, "mContentResolver is null");
+            return;
+        }
+        mContentResolver.unregisterContentObserver(mSettingsObserver);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 4714ff9..8a9f9dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -352,6 +352,8 @@
                         cachedDevice.setHiSyncId(newHiSyncId);
                     }
                 }
+
+                HearingAidStatsLogUtils.logHearingAidInfo(cachedDevice);
             }
 
             if (getCsipSetCoordinatorProfile() != null
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 766c036..7353cc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -407,7 +407,7 @@
                 || sessionInfo.getVolumeHandling() != MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
     }
 
-    private void refreshDevices() {
+    private synchronized void refreshDevices() {
         mMediaDevices.clear();
         mCurrentConnectedDevice = null;
         if (TextUtils.isEmpty(mPackageName)) {
@@ -437,7 +437,7 @@
         return infos;
     }
 
-    private void buildAvailableRoutes() {
+    private synchronized void buildAvailableRoutes() {
         for (MediaRoute2Info route : getAvailableRoutes(mPackageName)) {
             if (DEBUG) {
                 Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + ", volume : "
@@ -447,7 +447,7 @@
         }
     }
 
-    private List<MediaRoute2Info> getAvailableRoutes(String packageName) {
+    private synchronized List<MediaRoute2Info> getAvailableRoutes(String packageName) {
         final List<MediaRoute2Info> infos = new ArrayList<>();
         RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
         if (routingSessionInfo != null) {
@@ -571,7 +571,7 @@
 
         @Override
         public void onSessionUpdated(RoutingSessionInfo sessionInfo) {
-            dispatchDataChanged();
+            refreshDevices();
         }
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 63a9f0c..4ce88ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -21,8 +21,8 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -48,6 +48,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 
 class AvatarPhotoController {
@@ -326,13 +327,13 @@
 
         @Override
         public boolean startSystemActivityForResult(Intent intent, int code) {
-            ActivityInfo info = intent.resolveActivityInfo(mActivity.getPackageManager(),
-                    PackageManager.MATCH_SYSTEM_ONLY);
-            if (info == null) {
+            List<ResolveInfo> resolveInfos = mActivity.getPackageManager()
+                    .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
+            if (resolveInfos.isEmpty()) {
                 Log.w(TAG, "No system package activity could be found for code " + code);
                 return false;
             }
-            intent.setPackage(info.packageName);
+            intent.setPackage(resolveInfos.get(0).activityInfo.packageName);
             mActivity.startActivityForResult(intent, code);
             return true;
         }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index d80a591..611b0a4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -102,16 +102,25 @@
     }
 
     /**
-     * Test initHearingAidDeviceIfNeeded, a valid HiSyncId will be assigned
+     * Test initHearingAidDeviceIfNeeded, set HearingAid's information, including HiSyncId,
+     * deviceSide, deviceMode.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_validHiSyncId_verifyHiSyncId() {
+    public void initHearingAidDeviceIfNeeded_validHiSyncId_setHearingAidInfos() {
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
+        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
 
         assertThat(mCachedDevice1.getHiSyncId()).isNotEqualTo(HISYNCID1);
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1);
 
         assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+        assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
     }
 
     /**
@@ -251,6 +260,29 @@
     }
 
     /**
+     * Test updateHearingAidsDevices, set HearingAid's information, including HiSyncId, deviceSide,
+     * deviceMode.
+     */
+    @Test
+    public void updateHearingAidsDevices_validHiSyncId_setHearingAidInfos() {
+        when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
+        when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        when(mHearingAidProfile.getDeviceSide(mDevice1)).thenReturn(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.updateHearingAidsDevices();
+
+        assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
+        assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        verify(mHearingAidDeviceManager).onHiSyncIdChanged(HISYNCID1);
+    }
+
+    /**
      * Test onProfileConnectionStateChangedIfProcessed.
      * When first hearing aid device is connected, to process it same as other generic devices.
      * No need to process it.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
new file mode 100644
index 0000000..0cf5b89
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.HashMap;
+
+@RunWith(RobolectricTestRunner.class)
+public class HearingAidStatsLogUtilsTest {
+
+    private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+
+    @Test
+    public void setBondEntryForDevice_addsEntryToDeviceAddressToBondEntryMap() {
+        when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+
+        HearingAidStatsLogUtils.setBondEntryForDevice(
+                FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH,
+                mCachedBluetoothDevice);
+
+        final HashMap<String, Integer> map =
+                HearingAidStatsLogUtils.getDeviceAddressToBondEntryMap();
+        assertThat(map.containsKey(TEST_DEVICE_ADDRESS)).isTrue();
+        assertThat(map.get(TEST_DEVICE_ADDRESS)).isEqualTo(
+                FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH);
+    }
+
+    @Test
+    public void logHearingAidInfo_removesEntryFromDeviceAddressToBondEntryMap() {
+        when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+
+        HearingAidStatsLogUtils.setBondEntryForDevice(
+                FrameworkStatsLog.HEARING_AID_INFO_REPORTED__BOND_ENTRY__BLUETOOTH,
+                mCachedBluetoothDevice);
+        HearingAidStatsLogUtils.logHearingAidInfo(mCachedBluetoothDevice);
+
+        final HashMap<String, Integer> map =
+                HearingAidStatsLogUtils.getDeviceAddressToBondEntryMap();
+        assertThat(map.containsKey(TEST_DEVICE_ADDRESS)).isFalse();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index f4af6e8..33fb91d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -666,12 +666,22 @@
     }
 
     @Test
-    public void onSessionUpdated_shouldDispatchDataChanged() {
+    public void onSessionUpdated_shouldDispatchDeviceListAdded() {
+        final MediaRoute2Info info = mock(MediaRoute2Info.class);
+        when(info.getId()).thenReturn(TEST_ID);
+        when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(info.isSystemRoute()).thenReturn(true);
+
+        final List<MediaRoute2Info> routes = new ArrayList<>();
+        routes.add(info);
+        mShadowRouter2Manager.setAllRoutes(routes);
+
+        mInfoMediaManager.mPackageName = "";
         mInfoMediaManager.registerCallback(mCallback);
 
         mInfoMediaManager.mMediaRouterCallback.onSessionUpdated(mock(RoutingSessionInfo.class));
 
-        verify(mCallback).onDeviceAttributesChanged();
+        verify(mCallback).onDeviceListAdded(any());
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppHeaderPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppHeaderPreferenceTest.java
new file mode 100644
index 0000000..e2b242c
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppHeaderPreferenceTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceViewHolder;
+
+
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class AppHeaderPreferenceTest {
+
+    private Context mContext;
+    private View mRootView;
+    private AppHeaderPreference mPreference;
+    private PreferenceViewHolder mHolder;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mRootView = View.inflate(mContext, R.layout.app_header_preference, /* parent */ null);
+        mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
+        mPreference = new AppHeaderPreference(mContext);
+    }
+
+    @Test
+    public void setNonSelectable_viewShouldNotBeSelectable() {
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mHolder.itemView.isClickable()).isFalse();
+    }
+
+    @Test
+    public void defaultInstallType_viewShouldNotBeVisible() {
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mRootView.findViewById(R.id.install_type).getVisibility())
+                .isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setIsInstantApp_shouldUpdateInstallType() {
+        mPreference.onBindViewHolder(mHolder);
+        mPreference.setIsInstantApp(true);
+
+        assertThat(((TextView) mRootView.findViewById(R.id.install_type)).getText().toString())
+                .isEqualTo(mContext.getResources().getString(R.string.install_type_instant));
+    }
+
+    @Test
+    public void setSecondSummary_shouldUpdateSecondSummary() {
+        final String defaultTestText = "Test second summary";
+
+        mPreference.setSecondSummary(defaultTestText);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(((TextView) mRootView.findViewById(R.id.second_summary)).getText().toString())
+                .isEqualTo(defaultTestText);
+    }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index a941630..e8474de 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -218,5 +218,8 @@
         Settings.Secure.ACCESSIBILITY_SOFTWARE_CURSOR_KEYBOARD_SHIFT_ENABLED,
         Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED,
         Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED,
+        Settings.Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO,
+        Settings.Secure.BLUETOOTH_LE_BROADCAST_CODE,
+        Settings.Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 67ea024..0d52164 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -351,5 +351,8 @@
                 Secure.ACCESSIBILITY_SOFTWARE_CURSOR_TRIGGER_HINTS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_SOFTWARE_CURSOR_KEYBOARD_SHIFT_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_PROGRAM_INFO, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_CODE, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Secure.BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME, ANY_STRING_VALIDATOR);
     }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b31e36c..6c17036 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -180,6 +180,7 @@
     <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
     <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" />
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
index 85f2552..d55eda0 100644
--- a/packages/Shell/src/com/android/shell/Screenshooter.java
+++ b/packages/Shell/src/com/android/shell/Screenshooter.java
@@ -20,6 +20,7 @@
 import android.os.IBinder;
 import android.util.Log;
 import android.view.SurfaceControl;
+import android.window.ScreenCapture;
 
 /**
  * Helper class used to take screenshots.
@@ -40,11 +41,11 @@
         Log.d(TAG, "Taking fullscreen screenshot");
         // Take the screenshot
         final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-        final SurfaceControl.DisplayCaptureArgs captureArgs =
-                new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+        final ScreenCapture.DisplayCaptureArgs captureArgs =
+                new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
                         .build();
-        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                SurfaceControl.captureDisplay(captureArgs);
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                ScreenCapture.captureDisplay(captureArgs);
         final Bitmap screenShot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
         if (screenShot == null) {
             Log.e(TAG, "Failed to take fullscreen screenshot");
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7649de6..2737ecf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -414,7 +414,7 @@
             </intent-filter>
         </receiver>
 
-        <service android:name=".ImageWallpaper"
+        <service android:name=".wallpapers.ImageWallpaper"
                 android:singleUser="true"
                 android:permission="android.permission.BIND_WALLPAPER"
                 android:exported="true" />
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index e9cec70..3325eec 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -7,6 +7,7 @@
 aaliomer@google.com
 adamcohen@google.com
 alexflo@google.com
+arteiro@google.com
 asc@google.com
 awickham@google.com
 beverlyt@google.com
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 7d4dcf8..ebabdf57 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -352,8 +352,11 @@
          * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
          * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
          * before the cancellation.
+         *
+         * If this launch animation affected the occlusion state of the keyguard, WM will provide
+         * us with [newKeyguardOccludedState] so that we can set the occluded state appropriately.
          */
-        fun onLaunchAnimationCancelled() {}
+        fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {}
     }
 
     @VisibleForTesting
@@ -667,7 +670,7 @@
             removeTimeout()
             context.mainExecutor.execute {
                 animation?.cancel()
-                controller.onLaunchAnimationCancelled()
+                controller.onLaunchAnimationCancelled(newKeyguardOccludedState = isKeyguardOccluded)
             }
         }
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index eac5d275..9656b8a 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -238,7 +238,7 @@
                 }
             }
 
-            override fun onLaunchAnimationCancelled() {
+            override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
                 controller.onLaunchAnimationCancelled()
                 enableDialogDismiss()
                 dialog.dismiss()
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
new file mode 100644
index 0000000..b006615
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+
+/**
+ * Checks for slow calls to ActivityManager.getCurrentUser() or UserManager.getUserInfo() and
+ * suggests using UserTracker instead. For more info, see: http://go/multi-user-in-systemui-slides.
+ */
+@Suppress("UnstableApiUsage")
+class SlowUserQueryDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> {
+        return listOf("getCurrentUser", "getUserInfo")
+    }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        val evaluator = context.evaluator
+        if (
+            evaluator.isStatic(method) &&
+                method.name == "getCurrentUser" &&
+                method.containingClass?.qualifiedName == "android.app.ActivityManager"
+        ) {
+            context.report(
+                ISSUE_SLOW_USER_ID_QUERY,
+                method,
+                context.getNameLocation(node),
+                "ActivityManager.getCurrentUser() is slow. " +
+                    "Use UserTracker.getUserId() instead."
+            )
+        }
+        if (
+            !evaluator.isStatic(method) &&
+                method.name == "getUserInfo" &&
+                method.containingClass?.qualifiedName == "android.os.UserManager"
+        ) {
+            context.report(
+                ISSUE_SLOW_USER_INFO_QUERY,
+                method,
+                context.getNameLocation(node),
+                "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE_SLOW_USER_ID_QUERY: Issue =
+            Issue.create(
+                id = "SlowUserIdQuery",
+                briefDescription = "User ID queried using ActivityManager instead of UserTracker.",
+                explanation =
+                    "ActivityManager.getCurrentUser() makes a binder call and is slow. " +
+                        "Instead, inject a UserTracker and call UserTracker.getUserId(). For " +
+                        "more info, see: http://go/multi-user-in-systemui-slides",
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                    Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+            )
+
+        @JvmField
+        val ISSUE_SLOW_USER_INFO_QUERY: Issue =
+            Issue.create(
+                id = "SlowUserInfoQuery",
+                briefDescription = "User info queried using UserManager instead of UserTracker.",
+                explanation =
+                    "UserManager.getUserInfo() makes a binder call and is slow. " +
+                        "Instead, inject a UserTracker and call UserTracker.getUserInfo(). For " +
+                        "more info, see: http://go/multi-user-in-systemui-slides",
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                    Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index c7c73d3..4879883 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -30,6 +30,8 @@
         get() = listOf(
                 BindServiceViaContextDetector.ISSUE,
                 BroadcastSentViaContextDetector.ISSUE,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
                 GetMainLooperViaContextDetector.ISSUE,
                 RegisterReceiverViaContextDetector.ISSUE,
                 SoftwareBitmapDetector.ISSUE,
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
new file mode 100644
index 0000000..2738f04
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
@@ -0,0 +1,194 @@
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class SlowUserQueryDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = SlowUserQueryDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    override fun getIssues(): List<Issue> =
+        listOf(
+            SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+            SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+        )
+
+    @Test
+    fun testGetCurrentUser() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.app.ActivityManager;
+
+                        public class TestClass1 {
+                            public void slewlyGetCurrentUser() {
+                                ActivityManager.getCurrentUser();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectWarningCount(1)
+            .expectContains(
+                "ActivityManager.getCurrentUser() is slow. " +
+                    "Use UserTracker.getUserId() instead."
+            )
+    }
+
+    @Test
+    fun testGetUserInfo() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.os.UserManager;
+
+                        public class TestClass2 {
+                            public void slewlyGetUserInfo(UserManager userManager) {
+                                userManager.getUserInfo();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectWarningCount(1)
+            .expectContains(
+                "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+            )
+    }
+
+    @Test
+    fun testUserTrackerGetUserId() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import com.android.systemui.settings.UserTracker;
+
+                        public class TestClass3 {
+                            public void quicklyGetUserId(UserTracker userTracker) {
+                                userTracker.getUserId();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun testUserTrackerGetUserInfo() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import com.android.systemui.settings.UserTracker;
+
+                        public class TestClass4 {
+                            public void quicklyGetUserId(UserTracker userTracker) {
+                                userTracker.getUserInfo();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectClean()
+    }
+
+    private val activityManagerStub: TestFile =
+        java(
+            """
+            package android.app;
+
+            public class ActivityManager {
+                public static int getCurrentUser() {};
+            }
+            """
+        )
+
+    private val userManagerStub: TestFile =
+        java(
+            """
+            package android.os;
+            import android.content.pm.UserInfo;
+            import android.annotation.UserIdInt;
+
+            public class UserManager {
+                public UserInfo getUserInfo(@UserIdInt int userId) {};
+            }
+            """
+        )
+
+    private val userIdIntStub: TestFile =
+        java(
+            """
+            package android.annotation;
+
+            public @interface UserIdInt {}
+            """
+        )
+
+    private val userInfoStub: TestFile =
+        java(
+            """
+            package android.content.pm;
+
+            public class UserInfo {}
+            """
+        )
+
+    private val userTrackerStub: TestFile =
+        java(
+            """
+            package com.android.systemui.settings;
+            import android.content.pm.UserInfo;
+
+            public interface UserTracker {
+                public int getUserId();
+                public UserInfo getUserInfo();
+            }
+            """
+        )
+
+    private val stubs =
+        arrayOf(activityManagerStub, userManagerStub, userIdIntStub, userInfoStub, userTrackerStub)
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiButtons.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiButtons.kt
new file mode 100644
index 0000000..496f4b3
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/SystemUiButtons.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.compose
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ButtonColors
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+
+@Composable
+fun SysUiButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    content: @Composable RowScope.() -> Unit,
+) {
+    androidx.compose.material3.Button(
+        modifier = modifier.padding(vertical = 6.dp).height(36.dp),
+        colors = filledButtonColors(),
+        contentPadding = ButtonPaddings,
+        onClick = onClick,
+        enabled = enabled,
+    ) {
+        content()
+    }
+}
+
+@Composable
+fun SysUiOutlinedButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    content: @Composable RowScope.() -> Unit,
+) {
+    androidx.compose.material3.OutlinedButton(
+        modifier = modifier.padding(vertical = 6.dp).height(36.dp),
+        enabled = enabled,
+        colors = outlineButtonColors(),
+        border = outlineButtonBorder(),
+        contentPadding = ButtonPaddings,
+        onClick = onClick,
+    ) {
+        content()
+    }
+}
+
+@Composable
+fun SysUiTextButton(
+    onClick: () -> Unit,
+    modifier: Modifier = Modifier,
+    enabled: Boolean = true,
+    content: @Composable RowScope.() -> Unit,
+) {
+    androidx.compose.material3.TextButton(
+        onClick = onClick,
+        modifier = modifier,
+        enabled = enabled,
+        content = content,
+    )
+}
+
+private val ButtonPaddings = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
+
+@Composable
+private fun filledButtonColors(): ButtonColors {
+    val colors = LocalAndroidColorScheme.current
+    return ButtonDefaults.buttonColors(
+        containerColor = colors.colorAccentPrimary,
+        contentColor = colors.textColorOnAccent,
+    )
+}
+
+@Composable
+private fun outlineButtonColors(): ButtonColors {
+    val colors = LocalAndroidColorScheme.current
+    return ButtonDefaults.outlinedButtonColors(
+        contentColor = colors.textColorPrimary,
+    )
+}
+
+@Composable
+private fun outlineButtonBorder(): BorderStroke {
+    val colors = LocalAndroidColorScheme.current
+    return BorderStroke(
+        width = 1.dp,
+        color = colors.colorAccentPrimaryVariant,
+    )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/TextExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/TextExt.kt
new file mode 100644
index 0000000..e1f73e3
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/TextExt.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.common.ui.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import com.android.systemui.common.shared.model.Text
+
+/** Returns the loaded [String] or `null` if there isn't one. */
+@Composable
+fun Text.load(): String? {
+    return when (this) {
+        is Text.Loaded -> text
+        is Text.Resource -> stringResource(res)
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
new file mode 100644
index 0000000..3175dcf
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.compose
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import androidx.appcompat.content.res.AppCompatResources
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+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.fillMaxSize
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.android.systemui.common.ui.compose.load
+import com.android.systemui.compose.SysUiOutlinedButton
+import com.android.systemui.compose.SysUiTextButton
+import com.android.systemui.compose.features.R
+import com.android.systemui.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.user.ui.viewmodel.UserActionViewModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.user.ui.viewmodel.UserViewModel
+import java.lang.Integer.min
+import kotlin.math.ceil
+
+@Composable
+fun UserSwitcherScreen(
+    viewModel: UserSwitcherViewModel,
+    onFinished: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    val isFinishRequested: Boolean by viewModel.isFinishRequested.collectAsState(false)
+    val users: List<UserViewModel> by viewModel.users.collectAsState(emptyList())
+    val maxUserColumns: Int by viewModel.maximumUserColumns.collectAsState(1)
+    val menuActions: List<UserActionViewModel> by viewModel.menu.collectAsState(emptyList())
+    val isOpenMenuButtonVisible: Boolean by viewModel.isOpenMenuButtonVisible.collectAsState(false)
+    val isMenuVisible: Boolean by viewModel.isMenuVisible.collectAsState(false)
+
+    UserSwitcherScreenStateless(
+        isFinishRequested = isFinishRequested,
+        users = users,
+        maxUserColumns = maxUserColumns,
+        menuActions = menuActions,
+        isOpenMenuButtonVisible = isOpenMenuButtonVisible,
+        isMenuVisible = isMenuVisible,
+        onMenuClosed = viewModel::onMenuClosed,
+        onOpenMenuButtonClicked = viewModel::onOpenMenuButtonClicked,
+        onCancelButtonClicked = viewModel::onCancelButtonClicked,
+        onFinished = {
+            onFinished()
+            viewModel.onFinished()
+        },
+        modifier = modifier,
+    )
+}
+
+@Composable
+private fun UserSwitcherScreenStateless(
+    isFinishRequested: Boolean,
+    users: List<UserViewModel>,
+    maxUserColumns: Int,
+    menuActions: List<UserActionViewModel>,
+    isOpenMenuButtonVisible: Boolean,
+    isMenuVisible: Boolean,
+    onMenuClosed: () -> Unit,
+    onOpenMenuButtonClicked: () -> Unit,
+    onCancelButtonClicked: () -> Unit,
+    onFinished: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    LaunchedEffect(isFinishRequested) {
+        if (isFinishRequested) {
+            onFinished()
+        }
+    }
+
+    Box(
+        modifier =
+            modifier
+                .fillMaxSize()
+                .padding(
+                    horizontal = 60.dp,
+                    vertical = 40.dp,
+                ),
+    ) {
+        UserGrid(
+            users = users,
+            maxUserColumns = maxUserColumns,
+            modifier = Modifier.align(Alignment.Center),
+        )
+
+        Buttons(
+            menuActions = menuActions,
+            isOpenMenuButtonVisible = isOpenMenuButtonVisible,
+            isMenuVisible = isMenuVisible,
+            onMenuClosed = onMenuClosed,
+            onOpenMenuButtonClicked = onOpenMenuButtonClicked,
+            onCancelButtonClicked = onCancelButtonClicked,
+            modifier = Modifier.align(Alignment.BottomEnd),
+        )
+    }
+}
+
+@Composable
+private fun UserGrid(
+    users: List<UserViewModel>,
+    maxUserColumns: Int,
+    modifier: Modifier = Modifier,
+) {
+    Column(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        verticalArrangement = Arrangement.spacedBy(44.dp),
+        modifier = modifier,
+    ) {
+        val rowCount = ceil(users.size / maxUserColumns.toFloat()).toInt()
+        (0 until rowCount).forEach { rowIndex ->
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(64.dp),
+                modifier = modifier,
+            ) {
+                val fromIndex = rowIndex * maxUserColumns
+                val toIndex = min(users.size, (rowIndex + 1) * maxUserColumns)
+                users.subList(fromIndex, toIndex).forEach { user ->
+                    UserItem(
+                        viewModel = user,
+                    )
+                }
+            }
+        }
+    }
+}
+
+@Composable
+private fun UserItem(
+    viewModel: UserViewModel,
+) {
+    val onClicked = viewModel.onClicked
+    Column(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        modifier =
+            if (onClicked != null) {
+                    Modifier.clickable { onClicked() }
+                } else {
+                    Modifier
+                }
+                .alpha(viewModel.alpha),
+    ) {
+        Box {
+            UserItemBackground(modifier = Modifier.align(Alignment.Center).size(222.dp))
+
+            UserItemIcon(
+                image = viewModel.image,
+                isSelectionMarkerVisible = viewModel.isSelectionMarkerVisible,
+                modifier = Modifier.align(Alignment.Center).size(222.dp)
+            )
+        }
+
+        // User name
+        val text = viewModel.name.load()
+        if (text != null) {
+            // We use the box to center-align the text vertically as that is not possible with Text
+            // alone.
+            Box(
+                modifier = Modifier.size(width = 222.dp, height = 48.dp),
+            ) {
+                Text(
+                    text = text,
+                    style = MaterialTheme.typography.titleLarge,
+                    color = colorResource(com.android.internal.R.color.system_neutral1_50),
+                    maxLines = 1,
+                    overflow = TextOverflow.Ellipsis,
+                    modifier = Modifier.align(Alignment.Center),
+                )
+            }
+        }
+    }
+}
+
+@Composable
+private fun UserItemBackground(
+    modifier: Modifier = Modifier,
+) {
+    Image(
+        painter = ColorPainter(LocalAndroidColorScheme.current.colorBackground),
+        contentDescription = null,
+        modifier = modifier.clip(CircleShape),
+    )
+}
+
+@Composable
+private fun UserItemIcon(
+    image: Drawable,
+    isSelectionMarkerVisible: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    Image(
+        bitmap = image.toBitmap().asImageBitmap(),
+        contentDescription = null,
+        modifier =
+            if (isSelectionMarkerVisible) {
+                    // Draws a ring
+                    modifier.border(
+                        width = 8.dp,
+                        color = LocalAndroidColorScheme.current.colorAccentPrimary,
+                        shape = CircleShape,
+                    )
+                } else {
+                    modifier
+                }
+                .padding(16.dp)
+                .clip(CircleShape)
+    )
+}
+
+@Composable
+private fun Buttons(
+    menuActions: List<UserActionViewModel>,
+    isOpenMenuButtonVisible: Boolean,
+    isMenuVisible: Boolean,
+    onMenuClosed: () -> Unit,
+    onOpenMenuButtonClicked: () -> Unit,
+    onCancelButtonClicked: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    Row(
+        modifier = modifier,
+    ) {
+        // Cancel button.
+        SysUiTextButton(
+            onClick = onCancelButtonClicked,
+        ) {
+            Text(stringResource(R.string.cancel))
+        }
+
+        // "Open menu" button.
+        if (isOpenMenuButtonVisible) {
+            Spacer(modifier = Modifier.width(8.dp))
+            // To properly use a DropdownMenu in Compose, we need to wrap the button that opens it
+            // and the menu itself in a Box.
+            Box {
+                SysUiOutlinedButton(
+                    onClick = onOpenMenuButtonClicked,
+                ) {
+                    Text(stringResource(R.string.add))
+                }
+                Menu(
+                    viewModel = menuActions,
+                    isMenuVisible = isMenuVisible,
+                    onMenuClosed = onMenuClosed,
+                )
+            }
+        }
+    }
+}
+
+@Composable
+private fun Menu(
+    viewModel: List<UserActionViewModel>,
+    isMenuVisible: Boolean,
+    onMenuClosed: () -> Unit,
+    modifier: Modifier = Modifier,
+) {
+    val maxItemWidth = LocalConfiguration.current.screenWidthDp.dp / 4
+    DropdownMenu(
+        expanded = isMenuVisible,
+        onDismissRequest = onMenuClosed,
+        modifier =
+            modifier.background(
+                color = MaterialTheme.colorScheme.inverseOnSurface,
+            ),
+    ) {
+        viewModel.forEachIndexed { index, action ->
+            MenuItem(
+                viewModel = action,
+                onClicked = { action.onClicked() },
+                topPadding =
+                    if (index == 0) {
+                        16.dp
+                    } else {
+                        0.dp
+                    },
+                bottomPadding =
+                    if (index == viewModel.size - 1) {
+                        16.dp
+                    } else {
+                        0.dp
+                    },
+                modifier = Modifier.sizeIn(maxWidth = maxItemWidth),
+            )
+        }
+    }
+}
+
+@Composable
+private fun MenuItem(
+    viewModel: UserActionViewModel,
+    onClicked: () -> Unit,
+    topPadding: Dp,
+    bottomPadding: Dp,
+    modifier: Modifier = Modifier,
+) {
+    val context = LocalContext.current
+    val density = LocalDensity.current
+
+    val icon =
+        remember(viewModel.iconResourceId) {
+            val drawable =
+                checkNotNull(AppCompatResources.getDrawable(context, viewModel.iconResourceId))
+            drawable
+                .toBitmap(
+                    size = with(density) { 20.dp.toPx() }.toInt(),
+                    tintColor = Color.White,
+                )
+                .asImageBitmap()
+        }
+
+    DropdownMenuItem(
+        text = {
+            Text(
+                text = stringResource(viewModel.textResourceId),
+                style = MaterialTheme.typography.bodyMedium,
+            )
+        },
+        onClick = onClicked,
+        leadingIcon = {
+            Spacer(modifier = Modifier.width(10.dp))
+            Image(
+                bitmap = icon,
+                contentDescription = null,
+            )
+        },
+        modifier =
+            modifier
+                .heightIn(
+                    min = 56.dp,
+                )
+                .padding(
+                    start = 18.dp,
+                    end = 65.dp,
+                    top = topPadding,
+                    bottom = bottomPadding,
+                ),
+    )
+}
+
+/**
+ * Converts the [Drawable] to a [Bitmap].
+ *
+ * Note that this is a relatively memory-heavy operation as it allocates a whole bitmap and draws
+ * the `Drawable` onto it. Use sparingly and with care.
+ */
+private fun Drawable.toBitmap(
+    size: Int? = null,
+    tintColor: Color? = null,
+): Bitmap {
+    val bitmap =
+        if (intrinsicWidth <= 0 || intrinsicHeight <= 0) {
+            Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+        } else {
+            Bitmap.createBitmap(
+                size ?: intrinsicWidth,
+                size ?: intrinsicHeight,
+                Bitmap.Config.ARGB_8888
+            )
+        }
+    val canvas = Canvas(bitmap)
+    setBounds(0, 0, canvas.width, canvas.height)
+    if (tintColor != null) {
+        setTint(tintColor.toArgb())
+    }
+    draw(canvas)
+    return bitmap
+}
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg
new file mode 100644
index 0000000..6241b0b
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten1.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg
new file mode 100644
index 0000000..870ef13
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten2.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg
new file mode 100644
index 0000000..bb7261c
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten3.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg
new file mode 100644
index 0000000..e34b7dd
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten4.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg
new file mode 100644
index 0000000..9cde24b
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten5.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg b/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg
new file mode 100644
index 0000000..17825b6
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/res/drawable/kitten6.jpeg
Binary files differ
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt
new file mode 100644
index 0000000..881a1def
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ButtonsScreen.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+@file:OptIn(ExperimentalMaterial3Api::class)
+
+package com.android.systemui.compose.gallery
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.systemui.compose.SysUiButton
+import com.android.systemui.compose.SysUiOutlinedButton
+import com.android.systemui.compose.SysUiTextButton
+
+@Composable
+fun ButtonsScreen(
+    modifier: Modifier = Modifier,
+) {
+    Column(
+        modifier = modifier,
+    ) {
+        SysUiButton(
+            onClick = {},
+        ) {
+            Text("SysUiButton")
+        }
+
+        SysUiButton(
+            onClick = {},
+            enabled = false,
+        ) {
+            Text("SysUiButton - disabled")
+        }
+
+        SysUiOutlinedButton(
+            onClick = {},
+        ) {
+            Text("SysUiOutlinedButton")
+        }
+
+        SysUiOutlinedButton(
+            onClick = {},
+            enabled = false,
+        ) {
+            Text("SysUiOutlinedButton - disabled")
+        }
+
+        SysUiTextButton(
+            onClick = {},
+        ) {
+            Text("SysUiTextButton")
+        }
+
+        SysUiTextButton(
+            onClick = {},
+            enabled = false,
+        ) {
+            Text("SysUiTextButton - disabled")
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
index bb98fb3..6805bf8 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt
@@ -28,24 +28,25 @@
 
 /** The gallery app screens. */
 object GalleryAppScreens {
-    val Typography = ChildScreen("typography") { TypographyScreen() }
-    val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
-    val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
-    val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
+    private val Typography = ChildScreen("typography") { TypographyScreen() }
+    private val MaterialColors = ChildScreen("material_colors") { MaterialColorsScreen() }
+    private val AndroidColors = ChildScreen("android_colors") { AndroidColorsScreen() }
+    private val Buttons = ChildScreen("buttons") { ButtonsScreen() }
+    private val ExampleFeature = ChildScreen("example_feature") { ExampleFeatureScreen() }
 
-    val PeopleEmpty =
+    private val PeopleEmpty =
         ChildScreen("people_empty") { navController ->
             EmptyPeopleScreen(onResult = { navController.popBackStack() })
         }
-    val PeopleFew =
+    private val PeopleFew =
         ChildScreen("people_few") { navController ->
             FewPeopleScreen(onResult = { navController.popBackStack() })
         }
-    val PeopleFull =
+    private val PeopleFull =
         ChildScreen("people_full") { navController ->
             FullPeopleScreen(onResult = { navController.popBackStack() })
         }
-    val People =
+    private val People =
         ParentScreen(
             "people",
             mapOf(
@@ -54,6 +55,52 @@
                 "Full" to PeopleFull,
             )
         )
+    private val UserSwitcherSingleUser =
+        ChildScreen("user_switcher_single") { navController ->
+            UserSwitcherScreen(
+                userCount = 1,
+                onFinished = navController::popBackStack,
+            )
+        }
+    private val UserSwitcherThreeUsers =
+        ChildScreen("user_switcher_three") { navController ->
+            UserSwitcherScreen(
+                userCount = 3,
+                onFinished = navController::popBackStack,
+            )
+        }
+    private val UserSwitcherFourUsers =
+        ChildScreen("user_switcher_four") { navController ->
+            UserSwitcherScreen(
+                userCount = 4,
+                onFinished = navController::popBackStack,
+            )
+        }
+    private val UserSwitcherFiveUsers =
+        ChildScreen("user_switcher_five") { navController ->
+            UserSwitcherScreen(
+                userCount = 5,
+                onFinished = navController::popBackStack,
+            )
+        }
+    private val UserSwitcherSixUsers =
+        ChildScreen("user_switcher_six") { navController ->
+            UserSwitcherScreen(
+                userCount = 6,
+                onFinished = navController::popBackStack,
+            )
+        }
+    private val UserSwitcher =
+        ParentScreen(
+            "user_switcher",
+            mapOf(
+                "Single" to UserSwitcherSingleUser,
+                "Three" to UserSwitcherThreeUsers,
+                "Four" to UserSwitcherFourUsers,
+                "Five" to UserSwitcherFiveUsers,
+                "Six" to UserSwitcherSixUsers,
+            )
+        )
 
     val Home =
         ParentScreen(
@@ -63,7 +110,9 @@
                 "Material colors" to MaterialColors,
                 "Android colors" to AndroidColors,
                 "Example feature" to ExampleFeature,
+                "Buttons" to Buttons,
                 "People" to People,
+                "User Switcher" to UserSwitcher,
             )
         )
 }
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt
new file mode 100644
index 0000000..fe9707d
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/UserSwitcherScreen.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.compose.gallery
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import com.android.systemui.user.Fakes.fakeUserSwitcherViewModel
+import com.android.systemui.user.ui.compose.UserSwitcherScreen
+
+@Composable
+fun UserSwitcherScreen(
+    userCount: Int,
+    onFinished: () -> Unit,
+) {
+    val context = LocalContext.current.applicationContext
+    UserSwitcherScreen(
+        viewModel = fakeUserSwitcherViewModel(context, userCount = userCount),
+        onFinished = onFinished,
+    )
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
index 11477f9..6588e22 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
@@ -83,7 +83,11 @@
                 flowOf(
                     securityText?.let { text ->
                         SecurityButtonConfig(
-                            icon = Icon.Resource(R.drawable.ic_info_outline),
+                            icon =
+                                Icon.Resource(
+                                    R.drawable.ic_info_outline,
+                                    contentDescription = null,
+                                ),
                             text = text,
                             isClickable = securityClickable,
                         )
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
new file mode 100644
index 0000000..91a73ea
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user
+
+import android.content.Context
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.compose.gallery.R
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.mockito.mock
+
+object Fakes {
+    private val USER_TINT_COLORS =
+        arrayOf(
+            0x000000,
+            0x0000ff,
+            0x00ff00,
+            0x00ffff,
+            0xff0000,
+            0xff00ff,
+            0xffff00,
+            0xffffff,
+        )
+
+    fun fakeUserSwitcherViewModel(
+        context: Context,
+        userCount: Int,
+    ): UserSwitcherViewModel {
+        return UserSwitcherViewModel.Factory(
+                userInteractor =
+                    UserInteractor(
+                        repository =
+                            FakeUserRepository().apply {
+                                setUsers(
+                                    (0 until userCount).map { index ->
+                                        UserModel(
+                                            id = index,
+                                            name =
+                                                Text.Loaded(
+                                                    when (index % 6) {
+                                                        0 -> "Ross Geller"
+                                                        1 -> "Phoebe Buffay"
+                                                        2 -> "Monica Geller"
+                                                        3 -> "Rachel Greene"
+                                                        4 -> "Chandler Bing"
+                                                        else -> "Joey Tribbiani"
+                                                    }
+                                                ),
+                                            image =
+                                                checkNotNull(
+                                                    AppCompatResources.getDrawable(
+                                                        context,
+                                                        when (index % 6) {
+                                                            0 -> R.drawable.kitten1
+                                                            1 -> R.drawable.kitten2
+                                                            2 -> R.drawable.kitten3
+                                                            3 -> R.drawable.kitten4
+                                                            4 -> R.drawable.kitten5
+                                                            else -> R.drawable.kitten6
+                                                        },
+                                                    )
+                                                ),
+                                            isSelected = index == 0,
+                                            isSelectable = true,
+                                        )
+                                    }
+                                )
+                                setActions(
+                                    UserActionModel.values().mapNotNull {
+                                        if (it == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+                                            null
+                                        } else {
+                                            it
+                                        }
+                                    }
+                                )
+                            },
+                        controller = mock(),
+                        activityStarter = mock(),
+                        keyguardInteractor =
+                            KeyguardInteractor(
+                                repository =
+                                    FakeKeyguardRepository().apply { setKeyguardShowing(false) },
+                            ),
+                    ),
+                powerInteractor =
+                    PowerInteractor(
+                        repository = FakePowerRepository(),
+                    )
+            )
+            .create(UserSwitcherViewModel::class.java)
+    }
+}
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 7275712..bfbccb8 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -240,8 +240,6 @@
 -packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesManager.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -529,6 +527,8 @@
 -packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
 -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
 -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
 -packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
 -packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
 -packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
@@ -677,7 +677,6 @@
 -packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -834,6 +833,7 @@
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 57193e7..436145e 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -16,6 +16,8 @@
 
 import android.view.View;
 
+import androidx.annotation.FloatRange;
+
 import com.android.systemui.plugins.FragmentBase;
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -107,10 +109,24 @@
     void setInSplitShade(boolean shouldTranslate);
 
     /**
-     * Set the amount of pixels we have currently dragged down if we're transitioning to the full
-     * shade. 0.0f means we're not transitioning yet.
+     * Sets the progress of the transition to full shade on the lockscreen.
+     *
+     * @param isTransitioningToFullShade
+     *        whether the transition to full shade is in progress. This might be {@code true}, even
+     *        though {@code qsTransitionFraction} is still 0.
+     *        The reason for that is that on some device configurations, the QS transition has a
+     *        start delay compared to the overall transition.
+     *
+     * @param qsTransitionFraction
+     *        the fraction of the QS transition progress, from 0 to 1.
+     *
+     * @param qsSquishinessFraction
+     *        the fraction of the QS "squish" transition progress, from 0 to 1.
      */
-    default void setTransitionToFullShadeAmount(float pxAmount, float progress) {}
+    default void setTransitionToFullShadeProgress(
+            boolean isTransitioningToFullShade,
+            @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
+            @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {}
 
     /**
      * A rounded corner clipping that makes QS feel as if it were behind everything.
@@ -140,6 +156,12 @@
     default void setOverScrollAmount(int overScrollAmount) {}
 
     /**
+     * Sets whether the notification panel is using the full width of the screen. Typically true on
+     * small screens and false on large screens.
+     */
+    void setIsNotificationPanelFullWidth(boolean isFullWidth);
+
+    /**
      * Callback for when QSPanel container is scrolled
      */
     @ProvidesInterface(version = ScrollListener.VERSION)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
index 8bf982d..9c7fbe8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
@@ -3,7 +3,9 @@
 interface QSContainerController {
     fun setCustomizerAnimating(animating: Boolean)
 
-    fun setCustomizerShowing(showing: Boolean)
+    fun setCustomizerShowing(showing: Boolean) = setCustomizerShowing(showing, 0L)
+
+    fun setCustomizerShowing(showing: Boolean, animationDuration: Long)
 
     fun setDetailShowing(showing: Boolean)
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/res-keyguard/drawable/kg_bouncer_secondary_button.xml b/packages/SystemUI/res-keyguard/drawable/kg_bouncer_secondary_button.xml
new file mode 100644
index 0000000..732fc57
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/kg_bouncer_secondary_button.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:insetTop="6dp"
+    android:insetBottom="6dp">
+    <ripple android:color="?android:attr/colorControlHighlight">
+        <item android:id="@android:id/mask">
+            <shape android:shape="rectangle">
+                <solid android:color="?android:attr/textColorSecondary"/>
+                <corners android:radius="24dp"/>
+            </shape>
+        </item>
+        <item>
+            <shape android:shape="rectangle">
+                <corners android:radius="24dp"/>
+                <solid android:color="@android:color/transparent"/>
+                <stroke android:color="?androidprv:attr/colorAccentTertiary"
+                    android:width="1dp"
+                    />
+                <padding android:left="16dp"
+                    android:top="12dp"
+                    android:right="16dp"
+                    android:bottom="12dp"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml
new file mode 100644
index 0000000..5c0a7c8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_off.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="20"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c "
+                    android:valueTo="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="40"
+                    android:propertyName="pathData"
+                    android:startOffset="20"
+                    android:valueFrom="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+                    android:valueTo="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="40"
+                    android:propertyName="pathData"
+                    android:startOffset="60"
+                    android:valueFrom="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+                    android:valueTo="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="100"
+                    android:valueFrom="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+                    android:valueTo="M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="24dp"
+            android:height="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G"
+                    android:translateX="12"
+                    android:translateY="12">
+                    <path
+                        android:name="_R_G_L_0_G_D_0_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#ffffff"
+                        android:fillType="nonZero"
+                        android:pathData=" M0 -7.08 C-2.69,-7.08 -7.03,-5.19 -7.03,0.03 C-7.03,5.25 -2.19,7.08 0,7.08 C3.03,7.08 7.08,3.91 7.08,0 C7.08,-3.91 3.69,-7.08 0,-7.08c  M-8.33 0 C-8.33,-4.6 -4.6,-8.33 0,-8.33 C4.6,-8.33 8.33,-4.6 8.33,0 C8.33,4.6 4.6,8.33 0,8.33 C-4.6,8.33 -8.33,4.6 -8.33,0c " />
+                    <path
+                        android:name="_R_G_L_0_G_D_1_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#ffffff"
+                        android:fillType="nonZero"
+                        android:pathData=" M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c " />
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml
new file mode 100644
index 0000000..a96b748
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/qs_light_dark_theme_icon_on.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c "
+                    android:valueTo="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="pathData"
+                    android:startOffset="100"
+                    android:valueFrom="M3.11 -6.83 C-0.23,-9.49 -6.06,-6.24 -7.23,-2.29 C-7.28,-2.09 -7.23,1.85 -7.18,2.06 C-5.84,7.25 -0.33,9.23 3.14,6.75 C3.17,5.1 3.17,3.58 3.22,0 C3.25,-3.04 3.14,-5.1 3.11,-6.83c "
+                    android:valueTo="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="pathData"
+                    android:startOffset="167"
+                    android:valueFrom="M7.06 -3.94 C3.5,-8.81 -3.31,-9.44 -7,-3.66 C-7.12,-3.47 -7.05,3 -6.94,3.22 C-3.63,9.31 2.94,9.19 7,3.59 C7.06,1.94 7,3.19 7.12,0 C7.19,-2 7.12,-2.75 7.06,-3.94c "
+                    android:valueTo="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="233"
+                    android:valueFrom="M7.25 -2.44 C5.46,-5.86 1.53,-8.3 -1.72,-7.1 C-1.73,-6.22 -1.73,5.88 -1.7,7.16 C0.25,8.45 4.43,6.91 7.28,2.47 C7.29,1.42 7.27,1.3 7.3,0 C7.32,-1.17 7.27,-1.49 7.25,-2.44c "
+                    android:valueTo="M7.38 -2.03 C6.38,-4.66 3.47,-7.32 0.01,-7.32 C0.03,-6.22 -0.03,5.66 -0.03,7.28 C1.59,7.31 5.22,6.17 7.37,2.06 C7.37,1.21 7.37,0.69 7.37,0 C7.37,-0.91 7.38,-1.16 7.38,-2.03c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="350"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="24dp"
+            android:height="24dp"
+            android:viewportHeight="24"
+            android:viewportWidth="24">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G"
+                    android:translateX="12"
+                    android:translateY="12">
+                    <path
+                        android:name="_R_G_L_0_G_D_0_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#edf2eb"
+                        android:fillType="nonZero"
+                        android:pathData=" M0 -7.08 C-2.69,-7.08 -7.03,-5.19 -7.03,0.03 C-7.03,5.25 -2.19,7.08 0,7.08 C3.03,7.08 7.08,3.91 7.08,0 C7.08,-3.91 3.69,-7.08 0,-7.08c  M-8.33 0 C-8.33,-4.6 -4.6,-8.33 0,-8.33 C4.6,-8.33 8.33,-4.6 8.33,0 C8.33,4.6 4.6,8.33 0,8.33 C-4.6,8.33 -8.33,4.6 -8.33,0c " />
+                    <path
+                        android:name="_R_G_L_0_G_D_1_P_0"
+                        android:fillAlpha="1"
+                        android:fillColor="#edf2eb"
+                        android:fillType="nonZero"
+                        android:pathData=" M0 -7.49 C-2.58,-7.49 -7.45,-4.78 -7.45,-1.62 C-7.45,-1.42 -7.37,0.88 -7.37,1.09 C-7.37,6.31 -2.19,7.55 0,7.55 C0,5.91 -0.01,3.91 -0.01,0 C-0.01,-3.91 0,-5.31 0,-7.49c " />
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+</animated-vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
new file mode 100644
index 0000000..57b3acd
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.android.keyguard.BouncerKeyguardMessageArea
+        android:id="@+id/bouncer_message_area"
+        style="@style/Keyguard.TextView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/keyguard_lock_padding"
+        android:ellipsize="marquee"
+        android:focusable="true"
+        android:gravity="center"
+        android:singleLine="true" />
+</merge>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
index db508c9..67fd5b9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
@@ -17,15 +17,17 @@
 */
 -->
 
-<!-- This contains disable esim buttonas shared by sim_pin/sim_puk screens -->
-<com.android.keyguard.KeyguardEsimArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- This contains disable eSim buttons shared by sim_pin/sim_puk screens -->
+<com.android.keyguard.KeyguardEsimArea xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/keyguard_disable_esim"
+    style="@style/Keyguard.TextView"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:id="@+id/keyguard_disable_esim"
-    android:visibility="gone"
+    android:background="@drawable/kg_bouncer_secondary_button"
+    android:drawablePadding="10dp"
+    android:drawableStart="@drawable/ic_no_sim"
+    android:drawableTint="?android:attr/textColorPrimary"
     android:text="@string/disable_carrier_button_text"
-    style="@style/Keyguard.TextView"
-    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?android:attr/textColorPrimary"
     android:textSize="@dimen/kg_status_line_font_size"
-    android:textAllCaps="@bool/kg_use_all_caps" />
+    android:visibility="gone" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index e77e084..5486adb 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -28,6 +28,7 @@
     android:layout_gravity="center_horizontal|bottom"
     android:gravity="bottom"
     >
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
     <Space
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 231ead8..2b7bdc2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -31,6 +31,7 @@
     android:layout_gravity="center_horizontal|bottom"
     android:clipChildren="false"
     android:clipToPadding="false">
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/pattern_container"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 712f657..64ece47 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -17,23 +17,25 @@
 */
 -->
 
-<com.android.keyguard.KeyguardPINView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:id="@+id/keyguard_pin_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        androidprv:layout_maxWidth="@dimen/keyguard_security_width"
-        android:layout_gravity="center_horizontal|bottom"
-        android:orientation="vertical"
-        >
+<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pin_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="vertical"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width">
+<include layout="@layout/keyguard_bouncer_message_area"/>
 
-    <androidx.constraintlayout.widget.ConstraintLayout
+<androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/pin_container"
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_marginBottom="8dp"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:layout_weight="1"
         android:layoutDirection="ltr"
         android:orientation="vertical">
@@ -79,6 +81,8 @@
             android:layout_width="0dp"
             android:layout_height="0dp"
             android:orientation="horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false"
 
             androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
 
@@ -186,8 +190,6 @@
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
-
-
     <include layout="@layout/keyguard_eca"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index dae2e56..7db0fe9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -26,20 +26,17 @@
         android:layout_height="match_parent"
         androidprv:layout_maxWidth="@dimen/keyguard_security_width"
         android:layout_gravity="center_horizontal|bottom">
-
-  <Space
-      android:layout_width="match_parent"
-      android:layout_height="0dp"
-      android:layout_weight="1"
-      />
-
+    <include layout="@layout/keyguard_bouncer_message_area" />
+    <Space
+          android:layout_width="match_parent"
+          android:layout_height="0dp"
+          android:layout_weight="1" />
     <ImageView
             android:id="@+id/keyguard_sim"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:tint="@color/background_protected"
             android:src="@drawable/ic_lockscreen_sim"/>
-
     <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -50,16 +47,13 @@
         <include layout="@layout/keyguard_esim_area"
              android:id="@+id/keyguard_esim_area"
              android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:layout_marginTop="@dimen/eca_overlap" />
-
+             android:layout_height="wrap_content" />
         <RelativeLayout
                 android:id="@+id/row0"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingBottom="4dp"
                 >
-
             <com.android.keyguard.PasswordTextView
                 android:id="@+id/simPinEntry"
                 style="@style/Widget.TextView.Password"
@@ -195,7 +189,6 @@
                     />
         </LinearLayout>
     </LinearLayout>
-
     <include layout="@layout/keyguard_eca"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
@@ -205,5 +198,4 @@
              android:layout_marginTop="@dimen/keyguard_eca_top_margin"
              android:layout_marginBottom="2dp"
              android:gravity="center_horizontal"/>
-
 </com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 74f7820..422bd4c 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -27,12 +27,12 @@
         android:layout_height="match_parent"
         androidprv:layout_maxWidth="@dimen/keyguard_security_width"
         android:layout_gravity="center_horizontal|bottom">
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
-  <Space
-      android:layout_width="match_parent"
-      android:layout_height="0dp"
-      android:layout_weight="1"
-      />
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
 
     <ImageView
             android:id="@+id/keyguard_sim"
@@ -51,8 +51,7 @@
         <include layout="@layout/keyguard_esim_area"
             android:id="@+id/keyguard_esim_area"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/eca_overlap" />
+            android:layout_height="wrap_content" />
 
         <RelativeLayout
                 android:id="@+id/row0"
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index fc9c402..9dc054a 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Patrón incorrecto"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Contraseña incorrecta"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}other{Vuelve a intentarlo en # segundos.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}many{Vuelve a intentarlo en # segundos.}other{Vuelve a intentarlo en # segundos.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Ingresa el PIN de la tarjeta SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Ingresa el PIN de la tarjeta SIM de \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Inhabilita la tarjeta eSIM para usar el dispositivo sin servicio móvil."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Escribiste tu contraseña <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Dibujaste tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con tu proveedor para desbloquear el dispositivo."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{El código PIN de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}other{El código PIN de la tarjeta SIM es incorrecto. Tienes # intentos restantes. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{El código PIN de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}many{El código PIN de la tarjeta SIM es incorrecto. Tienes # intentos restantes. }other{El código PIN de la tarjeta SIM es incorrecto. Tienes # intentos restantes. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La tarjeta SIM no se puede usar. Comunícate con tu proveedor."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{El código PUK de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que la tarjeta SIM quede inutilizable permanentemente.}other{El código PUK de la tarjeta SIM es incorrecto. Tienes # intentos restantes antes de que la tarjeta SIM quede inutilizable permanentemente.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{El código PUK de la tarjeta SIM es incorrecto. Tienes # intento restante antes de que la tarjeta SIM quede inutilizable permanentemente.}many{El código PUK de la tarjeta SIM es incorrecto. Tienes # intentos restantes antes de que la tarjeta SIM quede inutilizable permanentemente.}other{El código PUK de la tarjeta SIM es incorrecto. Tienes # intentos restantes antes de que la tarjeta SIM quede inutilizable permanentemente.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Se produjo un error al desbloquear la tarjeta SIM con el PIN."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Se produjo un error al desbloquear la tarjeta SIM con el PUK."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de entrada"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se bloqueó de forma manual"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoció"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Activa acceso a cámara en Config. y usa Desb. facial"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Ingresa el PIN de la tarjeta SIM. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}other{Ingresa el PIN de la tarjeta SIM. Tienes # intentos restantes.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intento restante antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}other{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intentos restantes antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Ingresa el PIN de la tarjeta SIM. Tienes # intento restante antes de que debas comunicarte con tu operador para desbloquear el dispositivo.}many{Ingresa el PIN de la tarjeta SIM. Tienes # intentos restantes.}other{Ingresa el PIN de la tarjeta SIM. Tienes # intentos restantes.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intento restante antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}many{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intentos restantes antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}other{Se inhabilitó la tarjeta SIM. Para continuar, ingresa el código PUK. Tienes # intentos restantes antes de que la SIM quede inutilizable permanentemente. Comunícate con tu operador para conocer más detalles.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 4053161..f9f0452 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Patrón incorrecto"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Contraseña incorrecta"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorrecto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}other{Vuelve a intentarlo en # segundos.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Vuelve a intentarlo en # segundo.}many{Vuelve a intentarlo en # segundos.}other{Vuelve a intentarlo en # segundos.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduce el PIN de la tarjeta SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduce el PIN de la tarjeta SIM de <xliff:g id="CARRIER">%1$s</xliff:g>."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Inhabilita la tarjeta eSIM para usar el dispositivo sin servicio móvil."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al introducir la contraseña. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN de la SIM incorrecto. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}other{Código PIN de la SIM incorrecto. Te quedan # intentos. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN de la SIM incorrecto. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}many{Código PIN de la SIM incorrecto. Te quedan # intentos. }other{Código PIN de la SIM incorrecto. Te quedan # intentos. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La tarjeta SIM no se puede utilizar. Ponte en contacto con tu operador."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK de la SIM incorrecto. Te queda # intento antes de que la SIM quede inservible permanentemente.}other{Código PUK de la SIM incorrecto. Te quedan # intentos antes de que la SIM quede inservible permanentemente.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK de la SIM incorrecto. Te queda # intento antes de que la SIM quede inservible permanentemente.}many{Código PUK de la SIM incorrecto. Te quedan # intentos antes de que la SIM quede inservible permanentemente.}other{Código PUK de la SIM incorrecto. Te quedan # intentos antes de que la SIM quede inservible permanentemente.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"No se ha podido desbloquear la tarjeta SIM con el código PIN."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"No se ha podido desbloquear la tarjeta SIM con el código PUK."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambiar método de introducción"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se ha bloqueado manualmente"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoce"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Desbloqueo facial: activa el acceso a la cámara"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduce el PIN de la SIM. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}other{Introduce el PIN de la SIM. Te quedan # intentos.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te queda # intento antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}other{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te quedan # intentos antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduce el PIN de la SIM. Te queda # intento antes de tener que ponerte en contacto con tu operador para desbloquear el dispositivo.}many{Introduce el PIN de la SIM. Te quedan # intentos.}other{Introduce el PIN de la SIM. Te quedan # intentos.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te queda # intento antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}many{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te quedan # intentos antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}other{La SIM se ha inhabilitado. Introduce el código PUK para continuar. Te quedan # intentos antes de que la SIM quede inservible permanentemente. Ponte en contacto con tu operador para obtener más información.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 92ab77e..077fe11 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Schéma incorrect"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Mot de passe incorrect"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"NIP incorrect"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}other{Réessayez dans # secondes.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}many{Réessayez dans # secondes.}other{Réessayez dans # secondes.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Entrez le NIP de la carte SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Entrez le NIP de la carte SIM pour « <xliff:g id="CARRIER">%1$s</xliff:g> »."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Désactivez la carte eSIM pour utiliser l\'appareil sans service cellulaire."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez entré un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{NIP de la carte SIM incorrect. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{NIP de la carte SIM incorrect. Il vous reste # tentative. }other{NIP de la carte SIM incorrect. Il vous reste # tentatives. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{NIP de la carte SIM incorrect. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{NIP de la carte SIM incorrect. Il vous reste # tentative. }many{NIP de la carte SIM incorrect. Il vous reste # de tentatives. }other{NIP de la carte SIM incorrect. Il vous reste # tentatives. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La carte SIM est inutilisable. Communiquez avec votre fournisseur de services."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}one{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}other{Code PUK de la carte SIM incorrect. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}one{Code PUK de la carte SIM incorrect. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable.}many{Code PUK de la carte SIM incorrect. Il vous reste # de tentatives avant que votre carte SIM devienne définitivement inutilisable.}other{Code PUK de la carte SIM incorrect. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Le déverrouillage par NIP de la carte SIM a échoué."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Le déverrouillage de la carte SIM par code PUK a échoué."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer de méthode d\'entrée"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"L\'appareil a été verrouillé manuellement"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Doigt non reconnu"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Déverr. rec. faciale : activez accès app. photo dans Param."</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Entrez le NIP de la carte SIM. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{Entrez le NIP de la carte SIM. Il vous reste # tentative.}other{Entrez le NIP de la carte SIM. Il vous reste # tentatives.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}one{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}other{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Entrez le NIP de la carte SIM. Il vous reste # tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil.}one{Entrez le NIP de la carte SIM. Il vous reste # tentative.}many{Entrez le NIP de la carte SIM. Il vous reste # de tentatives.}other{Entrez le NIP de la carte SIM. Il vous reste # tentatives.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}one{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentative avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}many{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # de tentatives avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}other{La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste # tentatives avant que votre carte SIM devienne définitivement inutilisable. Communiquez avec votre fournisseur de services pour en savoir plus.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 01facd1..62379f8 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Schéma incorrect"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Mot de passe incorrect"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"Code incorrect"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}other{Réessayez dans # secondes.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Réessayez dans # seconde.}one{Réessayez dans # seconde.}many{Réessayez dans # secondes.}other{Réessayez dans # secondes.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Saisissez le code PIN de la carte SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Saisissez le code PIN de la carte SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Désactivez la carte eSIM pour utiliser l\'appareil sans service mobile."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Code PIN SIM incorrect. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Code PIN SIM incorrect. Il vous reste # tentative. }other{Code PIN SIM incorrect. Il vous reste # tentatives. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Code PIN SIM incorrect. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Code PIN SIM incorrect. Il vous reste # tentative. }many{Code PIN SIM incorrect. Il vous reste # tentatives. }other{Code PIN SIM incorrect. Il vous reste # tentatives. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"La carte SIM est inutilisable. Contactez votre opérateur."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable.}one{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la carte SIM ne devienne définitivement inutilisable.}other{Clé PUK de la SIM incorrecte. Il vous reste # tentatives avant que la carte SIM ne devienne définitivement inutilisable.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable.}one{Clé PUK de la SIM incorrecte. Il vous reste # tentative avant que la carte SIM ne devienne définitivement inutilisable.}many{Clé PUK de la SIM incorrecte. Il vous reste # tentatives avant que la carte SIM ne devienne définitivement inutilisable.}other{Clé PUK de la SIM incorrecte. Il vous reste # tentatives avant que la carte SIM ne devienne définitivement inutilisable.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Échec du déverrouillage à l\'aide du code PIN de la carte SIM."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Échec du déverrouillage à l\'aide de la clé PUK de la carte SIM."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Changer le mode de saisie"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Appareil verrouillé manuellement"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Non reconnu"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Pour le déverrouillage par reconnaissance faciale, activez l\'accès à l\'app. photo dans Paramètres"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Saisissez le code PIN SIM. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Saisissez le code PIN SIM. Il vous reste # tentative.}other{Saisissez le code PIN SIM. Il vous reste # tentatives.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}one{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}other{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentatives avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Saisissez le code PIN SIM. Il vous reste # tentative avant de devoir contacter votre opérateur pour déverrouiller l\'appareil.}one{Saisissez le code PIN SIM. Il vous reste # tentative.}many{Saisissez le code PIN SIM. Il vous reste # tentatives.}other{Saisissez le code PIN SIM. Il vous reste # tentatives.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}one{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentative avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}many{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentatives avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}other{La SIM est maintenant désactivée. Saisissez la clé PUK pour continuer. Il vous reste # tentatives avant que la SIM ne devienne définitivement inutilisable. Pour plus d\'infos, contactez votre opérateur.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index d3a683b..9fed5f7 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Sequenza errata"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Password errata"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN errato"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}other{Riprova fra # secondi.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Riprova fra # secondo.}many{Riprova fra # secondi.}other{Riprova fra # secondi.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Inserisci il PIN della SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disattiva la eSIM per usare il dispositivo senza servizio dati mobile."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Hai digitato la tua password <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Codice PIN della SIM errato. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}other{Codice PIN della SIM errato. Hai ancora # tentativi a disposizione. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Codice PIN della SIM errato. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}many{Codice PIN della SIM errato. Hai ancora # tentativi a disposizione. }other{Codice PIN della SIM errato. Hai ancora # tentativi a disposizione. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"SIM inutilizzabile. Contatta il tuo operatore."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Codice PUK della SIM errato. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.}other{Codice PUK della SIM errato. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Codice PUK della SIM errato. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.}many{Codice PUK della SIM errato. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.}other{Codice PUK della SIM errato. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Operazione con PIN della SIM non riuscita."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Operazione con PUK della SIM non riuscita."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Cambia metodo di immissione"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Il dispositivo è stato bloccato manualmente"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Sblocco con volto richiede l\'accesso alla fotocamera"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Inserisci il codice PIN della SIM. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}other{Inserisci il PIN della SIM. Hai a disposizione ancora # tentativi.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}other{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Inserisci il codice PIN della SIM. Hai ancora # tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.}many{Inserisci il PIN della SIM. Hai a disposizione ancora # tentativi.}other{Inserisci il PIN della SIM. Hai a disposizione ancora # tentativi.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}many{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}other{La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora # tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analogico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 76ced12..b934826 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Senha incorreta"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}other{Tente novamente em # segundos.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}many{Tente novamente em # segundos.}other{Tente novamente em # segundos.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Informe o PIN do chip."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }many{Código PIN do chip incorreto. Você tem # de tentativas restantes. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"O chip não pode ser utilizado. Entre em contato com a operadora."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}many{Código PUK do chip incorreto. Você tem # de tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha na operação de PIN do chip."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha na operação de PUK do chip."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Para usar o Desbloqueio facial, ative o acesso à câmera nas Configurações"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}many{Informe o PIN do chip. Você tem # de tentativas restantes.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}many{O chip está desativado. Informe o código PUK para continuar. Você tem # de tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Padrão"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bolha"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 94afc5f..a67bfb0 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto."</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Palavra-passe incorreta."</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}other{Tente novamente dentro de # segundos.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente dentro de # segundo.}many{Tente novamente dentro de # segundos.}other{Tente novamente dentro de # segundos.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Introduza o PIN do cartão SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para utilizar o dispositivo sem serviço móvel."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Introduziu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do SIM incorreto. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}other{Código PIN do SIM incorreto. Tem mais # tentativas. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do SIM incorreto. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}many{Código PIN do SIM incorreto. Tem mais # tentativas. }other{Código PIN do SIM incorreto. Tem mais # tentativas. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"Cartão SIM inutilizável. Contacte o seu operador."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do SIM incorreto. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável.}other{Código PUK do SIM incorreto. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do SIM incorreto. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável.}many{Código PUK do SIM incorreto. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável.}other{Código PUK do SIM incorreto. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha ao introduzir o PIN do cartão SIM!"</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha ao introduzir o PUK do cartão SIM!"</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alternar o método de introdução"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido."</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Ative acesso à câmara nas Def. p/ usar Desbl. facial"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduza o PIN do SIM. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}other{Introduza o PIN do SIM. Tem mais # tentativas.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}other{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduza o PIN do SIM. Tem mais # tentativa antes de ser necessário contactar o operador para desbloquear o dispositivo.}many{Introduza o PIN do SIM. Tem mais # tentativas.}other{Introduza o PIN do SIM. Tem mais # tentativas.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativa antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}many{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}other{O SIM está desativado. Introduza o código PUK para continuar. Tem mais # tentativas antes de o SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Predefinido"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Balão"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 76ced12..b934826 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -53,7 +53,7 @@
     <string name="kg_wrong_pattern" msgid="5907301342430102842">"Padrão incorreto"</string>
     <string name="kg_wrong_password" msgid="4143127991071670512">"Senha incorreta"</string>
     <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN incorreto"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}other{Tente novamente em # segundos.}}"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Tente novamente em # segundo.}one{Tente novamente em # segundo.}many{Tente novamente em # segundos.}other{Tente novamente em # segundos.}}"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Informe o PIN do chip."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Código PIN do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo.}one{Código PIN do chip incorreto. Você tem # tentativa restante. }many{Código PIN do chip incorreto. Você tem # de tentativas restantes. }other{Código PIN do chip incorreto. Você tem # tentativas restantes. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"O chip não pode ser utilizado. Entre em contato com a operadora."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}one{Código PUK do chip incorreto. Você tem # tentativa restante. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}many{Código PUK do chip incorreto. Você tem # de tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}other{Código PUK do chip incorreto. Você tem # tentativas restantes. Se o código correto não for digitado, o chip vai ficar permanentemente inutilizável.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Falha na operação de PIN do chip."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Falha na operação de PUK do chip."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Alterar o método de entrada"</string>
@@ -85,8 +85,8 @@
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo foi bloqueado manualmente"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Não reconhecido"</string>
     <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Para usar o Desbloqueio facial, ative o acesso à câmera nas Configurações"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Informe o PIN do chip. Você tem # tentativa restante antes de precisar entrar em contato com a operadora para desbloquear seu dispositivo.}one{Informe o PIN do chip. Você tem # tentativa restante.}many{Informe o PIN do chip. Você tem # de tentativas restantes.}other{Informe o PIN do chip. Você tem # tentativas restantes.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}one{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativa restante antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}many{O chip está desativado. Informe o código PUK para continuar. Você tem # de tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}other{O chip está desativado. Informe o código PUK para continuar. Você tem # tentativas restantes antes que o chip fique permanentemente inutilizável. Consulte sua operadora para saber mais.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Padrão"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Bolha"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index e80cfaf..a1068c6 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -31,8 +31,4 @@
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">100dp</dimen>
     <dimen name="widget_label_font_size">18sp</dimen>
-
-    <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
-         Should be 0 on devices with plenty of room (e.g. tablets) -->
-    <dimen name="eca_overlap">0dip</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 32871f0..46f6ab2 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -44,10 +44,6 @@
     <dimen name="keyguard_eca_top_margin">18dp</dimen>
     <dimen name="keyguard_eca_bottom_margin">12dp</dimen>
 
-    <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
-         Should be 0 on devices with plenty of room (e.g. tablets) -->
-    <dimen name="eca_overlap">-10dip</dimen>
-
     <!-- Slice header -->
     <dimen name="widget_title_font_size">20dp</dimen>
     <dimen name="widget_title_line_height">24dp</dimen>
@@ -84,6 +80,10 @@
     <!-- The translation for disappearing security views after having solved them. -->
     <dimen name="disappear_y_translation">-32dp</dimen>
 
+    <!-- Dimens for animation for the Bouncer PIN view -->
+    <dimen name="pin_view_trans_y_entry">120dp</dimen>
+    <dimen name="pin_view_trans_y_entry_offset">10dp</dimen>
+
     <!-- Spacing around each button used for PIN view -->
     <dimen name="num_pad_key_width">72dp</dimen>
     <dimen name="num_pad_entry_row_margin_bottom">12dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index deab610..04dffb6 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -50,7 +50,7 @@
         <item name="android:background">@null</item>
         <item name="android:textSize">32sp</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
         <item name="android:paddingBottom">-16dp</item>
     </style>
     <style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
diff --git a/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml b/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml
index 1ab0d4d..92c9527 100644
--- a/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml
+++ b/packages/SystemUI/res/drawable/ic_magnification_menu_large.xml
@@ -14,12 +14,12 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:width="24dp"
-    android:height="24dp">
-    <path
-        android:pathData="M3 21L21 21C22.1 21 23 20.1 23 19L23 5C23 3.9 22.1 3 21 3L3 3C1.9 3 1 3.9 1 5L1 19C1 20.1 1.9 21 3 21ZM3 5L21 5L21 19L3 19L3 5ZM4 15L16.75 15L16.75 6L4 6L4 15Z"
-        android:fillType="evenOdd"
-        android:fillColor="#000000" />
-</vector>
\ No newline at end of file
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M9.7,29.6H33.75V13.7H9.7ZM7,40Q5.8,40 4.9,39.1Q4,38.2 4,37V11Q4,9.8 4.9,8.9Q5.8,8 7,8H41Q42.2,8 43.1,8.9Q44,9.8 44,11V37Q44,38.2 43.1,39.1Q42.2,40 41,40ZM7,37H41Q41,37 41,37Q41,37 41,37V11Q41,11 41,11Q41,11 41,11H7Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37ZM7,37Q7,37 7,37Q7,37 7,37V11Q7,11 7,11Q7,11 7,11Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml b/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml
index 6fc89a6..209681f 100644
--- a/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml
+++ b/packages/SystemUI/res/drawable/ic_magnification_menu_medium.xml
@@ -14,12 +14,12 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:width="24dp"
-    android:height="24dp">
-    <path
-        android:pathData="M3 21L21 21C22.1 21 23 20.1 23 19L23 5C23 3.9 22.1 3 21 3L3 3C1.9 3 1 3.9 1 5L1 19C1 20.1 1.9 21 3 21ZM3 5L21 5L21 19L3 19L3 5ZM4 12.75L13.75 12.75L13.75 6L4 6L4 12.75Z"
-        android:fillType="evenOdd"
-        android:fillColor="#000000" />
-</vector>
\ No newline at end of file
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M9.7,27.6H27.75V13.7H9.7ZM7,40Q5.8,40 4.9,39.1Q4,38.2 4,37V11Q4,9.8 4.9,8.9Q5.8,8 7,8H41Q42.2,8 43.1,8.9Q44,9.8 44,11V37Q44,38.2 43.1,39.1Q42.2,40 41,40ZM7,37H41Q41,37 41,37Q41,37 41,37V11Q41,11 41,11Q41,11 41,11H7Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37ZM7,37Q7,37 7,37Q7,37 7,37V11Q7,11 7,11Q7,11 7,11Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml b/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml
index fd73574..a3dc816 100644
--- a/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml
+++ b/packages/SystemUI/res/drawable/ic_magnification_menu_small.xml
@@ -14,12 +14,12 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:width="24dp"
-    android:height="24dp">
-    <path
-        android:pathData="M3 21L21 21C22.1 21 23 20.1 23 19L23 5C23 3.9 22.1 3 21 3L3 3C1.9 3 1 3.9 1 5L1 19C1 20.1 1.9 21 3 21ZM3 5L21 5L21 19L3 19L3 5ZM4 10.5L8.5 10.5L8.5 6L4 6L4 10.5Z"
-        android:fillType="evenOdd"
-        android:fillColor="#000000" />
-</vector>
\ No newline at end of file
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M9.7,21.6H17.75V13.7H9.7ZM7,40Q5.8,40 4.9,39.1Q4,38.2 4,37V11Q4,9.8 4.9,8.9Q5.8,8 7,8H41Q42.2,8 43.1,8.9Q44,9.8 44,11V37Q44,38.2 43.1,39.1Q42.2,40 41,40ZM7,37H41Q41,37 41,37Q41,37 41,37V11Q41,11 41,11Q41,11 41,11H7Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37ZM7,37Q7,37 7,37Q7,37 7,37V11Q7,11 7,11Q7,11 7,11Q7,11 7,11Q7,11 7,11V37Q7,37 7,37Q7,37 7,37Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_move_magnification.xml b/packages/SystemUI/res/drawable/ic_move_magnification.xml
index 1bff559..dfedd28 100644
--- a/packages/SystemUI/res/drawable/ic_move_magnification.xml
+++ b/packages/SystemUI/res/drawable/ic_move_magnification.xml
@@ -1,43 +1,25 @@
-<?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.
-  -->
+     Copyright (C) 2020 The Android Open Source Project
 
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item>
-        <shape android:shape="rectangle">
-            <solid
-                android:color="@color/magnification_drag_handle_color" />
-            <size
-                android:height="@dimen/magnification_drag_view_size"
-                android:width="@dimen/magnification_drag_view_size"/>
-            <corners android:topLeftRadius="12dp"/>
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
 
-        </shape>
-    </item>
-    <item
-        android:gravity="center">
+          http://www.apache.org/licenses/LICENSE-2.0
 
-        <vector xmlns:android="http://schemas.android.com/apk/res/android"
-            android:viewportWidth="24"
-            android:viewportHeight="24"
-            android:width="24dp"
-            android:height="24dp">
-            <path
-                android:pathData="M13.2217 21.7734C12.8857 22.1094 12.288 22.712 12 23C12 23 11.1143 22.1094 10.7783 21.7734L8.33494 19.3301L9.55662 18.1084L12 20.5518L14.4434 18.1084L15.665 19.3301L13.2217 21.7734ZM19.3301 15.665L18.1084 14.4433L20.5518 12L18.1084 9.5566L19.3301 8.33492L21.7735 10.7783C22.1094 11.1142 22.4241 11.4241 23 12C22.4241 12.5759 22.3963 12.5988 21.7735 13.2217L19.3301 15.665ZM14.4434 14.4433C13.7714 15.1153 12.957 15.4512 12 15.4512C11.043 15.4512 10.2285 15.1153 9.55662 14.4433C8.88469 13.7714 8.54873 12.957 8.54873 12C8.54873 11.043 8.88469 10.2285 9.55662 9.5566C10.2285 8.88468 11.043 8.54871 12 8.54871C12.957 8.54871 13.7714 8.88467 14.4434 9.5566C15.1153 10.2285 15.4512 11.043 15.4512 12C15.4512 12.957 15.1153 13.7714 14.4434 14.4433ZM4.66988 15.665L2.22651 13.2217C1.89055 12.8857 1.28791 12.288 1 12C1.28791 11.712 1.89055 11.1143 2.22651 10.7783L4.66988 8.33492L5.89157 9.5566L3.4482 12L5.89157 14.4433L4.66988 15.665ZM14.4434 5.89155L12 3.44818L9.55662 5.89155L8.33494 4.66987L10.7783 2.2265C11.1389 1.86592 11.2963 1.70369 12 1C12.5758 1.57585 12.8857 1.89053 13.2217 2.2265L15.665 4.66986L14.4434 5.89155Z"
-                android:fillColor="#ffffff" />
-        </vector>
-    </item>
-</layer-list>
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M12,15Q10.75,15 9.875,14.125Q9,13.25 9,12Q9,10.75 9.875,9.875Q10.75,9 12,9Q13.25,9 14.125,9.875Q15,10.75 15,12Q15,13.25 14.125,14.125Q13.25,15 12,15ZM12,22 L7.75,17.75 9.15,16.35 12,19.15 14.85,16.35 16.25,17.75ZM6.25,16.25 L2,12 6.25,7.75 7.65,9.15 4.85,12 7.65,14.85ZM9.15,7.65 L7.75,6.25 12,2 16.25,6.25 14.85,7.65 12,4.85ZM17.75,16.25 L16.35,14.85 19.15,12 16.35,9.15 17.75,7.75 22,12Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_no_sim.xml b/packages/SystemUI/res/drawable/ic_no_sim.xml
new file mode 100644
index 0000000..ccfb6ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_no_sim.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M20,17.175 L18,15.175V4Q18,4 18,4Q18,4 18,4H10.85L8.85,6L7.4,4.6L10,2H18Q18.825,2 19.413,2.587Q20,3.175 20,4ZM20.5,23.3 L6,8.8V20Q6,20 6,20Q6,20 6,20H18Q18,20 18,20Q18,20 18,20V17.975L20,19.975V20Q20,20.825 19.413,21.413Q18.825,22 18,22H6Q5.175,22 4.588,21.413Q4,20.825 4,20V8L4.6,7.4L0.7,3.5L2.125,2.1L21.9,21.875ZM13.525,10.675Q13.525,10.675 13.525,10.675Q13.525,10.675 13.525,10.675ZM11.65,14.475Q11.65,14.475 11.65,14.475Q11.65,14.475 11.65,14.475Q11.65,14.475 11.65,14.475Q11.65,14.475 11.65,14.475Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
new file mode 100644
index 0000000..40bfd83
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_dialog_background.xml
@@ -0,0 +1,22 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners
+        android:radius="28dp"/>
+    <solid android:color="@color/media_dialog_background" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/media_seekbar_thumb.xml b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
new file mode 100644
index 0000000..5eb2bfd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
@@ -0,0 +1,50 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector android:height="16dp"
+                android:width="4dp"
+                android:viewportHeight="16"
+                android:viewportWidth="4">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_0_G"
+                       android:translateX="2"
+                       android:translateY="8">
+                    <path android:name="_R_G_L_0_G_D_0_P_0"
+                          android:fillColor="#ffffff"
+                          android:fillAlpha="1"
+                          android:fillType="nonZero"
+                          android:pathData=" M2 -6 C2,-6 2,6 2,6 C2,7.1 1.1,8 0,8 C0,8 0,8 0,8 C-1.1,8 -2,7.1 -2,6 C-2,6 -2,-6 -2,-6 C-2,-7.1 -1.1,-8 0,-8 C0,-8 0,-8 0,-8 C1.1,-8 2,-7.1 2,-6c "/>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateX"
+                                android:duration="1017"
+                                android:startOffset="0"
+                                android:valueFrom="0"
+                                android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index d633803..be76405 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -51,7 +51,7 @@
         android:id="@+id/biometric_icon_frame"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal">
+        android:layout_gravity="center">
 
         <com.airbnb.lottie.LottieAnimationView
             android:id="@+id/biometric_icon"
@@ -61,6 +61,13 @@
             android:contentDescription="@null"
             android:scaleType="fitXY" />
 
+        <com.airbnb.lottie.LottieAnimationView
+            android:id="@+id/biometric_icon_overlay"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            android:scaleType="fitXY" />
     </FrameLayout>
 
     <!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index c972624..006b260 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -40,7 +40,6 @@
         android:layout_height="match_parent"
         android:orientation="horizontal"
         android:gravity="center_vertical"
-        android:layout_marginEnd="@dimen/dream_overlay_status_bar_extra_margin"
         app:layout_constraintEnd_toStartOf="@+id/dream_overlay_system_status" />
 
     <LinearLayout
@@ -48,14 +47,15 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:orientation="horizontal"
-        android:layout_marginStart="@dimen/dream_overlay_status_bar_extra_margin"
+        android:paddingStart="@dimen/dream_overlay_status_bar_extra_margin"
+        android:visibility="gone"
         app:layout_constraintEnd_toEndOf="parent">
 
         <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"
-            android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
             android:src="@drawable/ic_alarm"
             android:tint="@android:color/white"
             android:visibility="gone"
@@ -65,7 +65,7 @@
             android:id="@+id/dream_overlay_priority_mode"
             android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
             android:src="@drawable/ic_qs_dnd_on"
             android:tint="@android:color/white"
             android:visibility="gone"
@@ -75,7 +75,7 @@
             android:id="@+id/dream_overlay_wifi_status"
             android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
             android:src="@drawable/ic_signal_wifi_off"
             android:visibility="gone"
             android:contentDescription="@string/dream_overlay_status_bar_wifi_off" />
@@ -84,7 +84,7 @@
             android:id="@+id/dream_overlay_mic_off"
             android:layout_width="@dimen/dream_overlay_grey_chip_width"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
             android:src="@drawable/dream_overlay_mic_off"
             android:visibility="gone"
             android:contentDescription="@string/dream_overlay_status_bar_mic_off" />
@@ -93,7 +93,7 @@
             android:id="@+id/dream_overlay_camera_off"
             android:layout_width="@dimen/dream_overlay_grey_chip_width"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
             android:src="@drawable/dream_overlay_camera_off"
             android:visibility="gone"
             android:contentDescription="@string/dream_overlay_status_bar_camera_off" />
@@ -102,7 +102,7 @@
             android:id="@+id/dream_overlay_camera_mic_off"
             android:layout_width="@dimen/dream_overlay_grey_chip_width"
             android:layout_height="match_parent"
-            android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+            android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
             android:src="@drawable/dream_overlay_mic_and_camera_off"
             android:visibility="gone"
             android:contentDescription="@string/dream_overlay_status_bar_camera_mic_off" />
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 0ca19d9..8df8c49 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -83,48 +83,6 @@
         android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
         android:visibility="gone" />
 
-    <ImageView
-        android:id="@+id/wallet_button"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|end"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_wallet_lockscreen"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
-        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-        android:contentDescription="@string/accessibility_wallet_button"
-        android:visibility="gone" />
-
-    <ImageView
-        android:id="@+id/qr_code_scanner_button"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|end"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_qr_code_scanner"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
-        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-        android:contentDescription="@string/accessibility_qr_code_scanner_button"
-        android:visibility="gone" />
-
-    <ImageView
-        android:id="@+id/controls_button"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|start"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/controls_icon"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
-        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-        android:contentDescription="@string/quick_controls_title"
-        android:visibility="gone" />
-
     <FrameLayout
         android:id="@+id/overlay_container"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 93c16e4..b76de5a 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -20,6 +20,7 @@
     android:id="@+id/media_output_dialog"
     android:layout_width="@dimen/large_dialog_width"
     android:layout_height="wrap_content"
+    android:background="@drawable/media_output_dialog_background"
     android:orientation="vertical">
 
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 86f8ce2..0c57b934 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -88,7 +88,7 @@
         android:layout_marginTop="@dimen/status_bar_height"
         android:layout_gravity="top|center_horizontal"
         android:gravity="center_horizontal">
-        <com.android.keyguard.KeyguardMessageArea
+        <com.android.keyguard.AuthKeyguardMessageArea
             android:id="@+id/keyguard_message_area"
             style="@style/Keyguard.TextView"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json b/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json
new file mode 100644
index 0000000..3d33b2a
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Symbol_Fingerprint_To_Error_Landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_landscape_base.json b/packages/SystemUI/res/raw/biometricprompt_landscape_base.json
new file mode 100644
index 0000000..3781eee
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_landscape_base.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_landscape_base","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json
new file mode 100644
index 0000000..4950666
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"biometricprompt_landscape_base","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}]}],"layers":[{"ddd":0,"ind":6,"ty":0,"nm":"biometricprompt_landscape_base","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[170,170,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":340,"h":340,"ip":0,"op":900,"st":0,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json b/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json
new file mode 100644
index 0000000..b161609
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_topleft","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":6,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null_Circle","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey905","cl":"grey905","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"circle mask 3","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Finger_Flipped","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-24.98,-35.709,0],"ix":2,"l":2},"a":{"a":0,"k":[31.791,75.23,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.03,5.25],[-2.83,8.98],[-5.59,-0.26],[2.52,-11.02]],"o":[[-2.85,12.77],[2.07,-14.96],[1.9,-6],[1.4,8.05],[0,0]],"v":[[7.5,4.99],[-10.09,19.69],[-3.59,-16.61],[8.69,-24.92],[7.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.8,24.94],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.01,22.23],[-1.2,-27.39],[4.09,-26.79],[15.73,14.18]],"o":[[5.64,-17.93],[2.45,56.06],[-22.4,-1.77],[17.73,-51.82]],"v":[[-7.57,-66.9],[30.82,-44.76],[26.65,75.23],[-31.78,50.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[31.79,75.23],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"circle mask 7","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey600","cl":"grey600","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle mask","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey904","cl":"grey904","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"circle mask 6","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey903","cl":"grey903","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"circle mask 2","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".blue400","cl":"blue400","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"circle mask 4","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":1,"nm":".grey902","cl":"grey902","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"circle mask 5","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":1,"nm":".black","cl":"black","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".grey800","cl":"grey800","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".grey901","cl":"grey901","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-87.156,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[100.25,-94.656,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 4","parent":6,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":".grey900","cl":"grey900","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json
new file mode 100644
index 0000000..034ac87
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json
new file mode 100644
index 0000000..e5cc565e
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json
new file mode 100644
index 0000000..b082265
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json
new file mode 100644
index 0000000..befe3bb
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json
new file mode 100644
index 0000000..d75b335
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 13","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json
new file mode 100644
index 0000000..e6b2db1
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 13","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json
new file mode 100644
index 0000000..0da143c
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_error_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json
new file mode 100644
index 0000000..15457c7
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_error_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json
new file mode 100644
index 0000000..f39894b
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json
new file mode 100644
index 0000000..6d4f4e2
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 15","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json
new file mode 100644
index 0000000..b7bb0d5
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 15","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b5e93e8..7f6f006 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Kan nie gesig herken nie"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gebruik eerder vingerafdruk"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth gekoppel."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterypersentasie is onbekend."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Onderskrifteoorlegger"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktiveer"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiveer"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Klank en vibrasie"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Instellings"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Program is vasgespeld"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig om dit te ontspeld."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Tuis om dit te ontspeld."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Af"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Onbeskikbaar"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Gedeaktiveer"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"kom meer te wete"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigasiebalk"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Uitleg"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra linksknoppie-tipe"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Sommige kenmerke is beperk terwyl foon afkoel.\nTik vir meer inligting"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Jou foon sal outomaties probeer om af te koel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger wees.\n\nJou foon sal normaalweg werk nadat dit afgekoel het."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sien versorgingstappe"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Trek laaier uit"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kan nie hierdie toestel laai nie. Trek die kragprop uit, en wees versigtig, want die kabel kan warm wees."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Sien versorgingstappe"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Links-kortpad"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Regs-kortpad"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index aee5153..a3ebb60 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"መልክን መለየት አልተቻለም"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"በምትኩ የጣት አሻራን ይጠቀሙ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ብሉቱዝ ተያይዟል።"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"የባትሪ መቶኛ አይታወቅም።"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በፍጥነት ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"የሥዕል መግለጫ ጽሑፎች ንብርብር"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"አንቃ"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"አሰናክል"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ድምጽ እና ንዝረት"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ቅንብሮች"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"መተግበሪያ ተሰክቷል"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና አጠቃላይ ዕይታ የሚለውን ይጫኑ እና ይያዙ።"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና መነሻ የሚለውን ይንኩ እና ይያዙ።"</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"በርቷል"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ጠፍቷል"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"አይገኝም"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ተሰናክሏል"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"የአሰሳ አሞሌ"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"አቀማመጥ"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ተጨማሪ የግራ አዝራር ዓይነት"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"አንዳንድ ባሕሪያት ስልኩ እየቀዘቀዘ እያለ ውስን ይሆናሉ።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ፣ ነገር ግን ሊንቀራፈፍ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኝነት ያሄዳል።"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ኃይል መሙያን ይንቀሉ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"የዚህን መሣሪያ ባትሪ መሙላት ላይ ችግር አለ። የኃይል አስማሚውን ይንቀሉትና ሊግል ስለሚችል ገመዱን ይጠብቁት።"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"የግራ አቋራጭ"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"የቀኝ አቋራጭ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 7a2d5caf..5a35e90 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"واجهة مستخدم النظام"</string>
     <string name="battery_low_title" msgid="5319680173344341779">"هل تريد تفعيل ميزة \"توفير شحن البطارية\"؟"</string>
-    <string name="battery_low_description" msgid="3282977755476423966">"يتبقى لديك <xliff:g id="PERCENTAGE">%s</xliff:g> من شحن البطارية. يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"يتبقى لديك <xliff:g id="PERCENTAGE">%s</xliff:g> من شحن البطارية. يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وحظر الأنشطة في الخلفية وتأخير الإشعارات."</string>
     <string name="battery_low_intro" msgid="5148725009653088790">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد الأنشطة في الخلفية وتأخير الإشعارات."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"متبقي <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"‏يتعذّر الشحن باستخدام USB."</string>
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"يتعذّر التعرّف على الوجه."</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"يمكنك استخدام بصمة إصبعك."</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"تم توصيل البلوتوث."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"تراكب الشرح"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"تفعيل"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"إيقاف"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"الصوت والاهتزاز"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"الإعدادات"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت الشاشة على التطبيق"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"مفعّل"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"متوقف"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"غير متوفّر"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"غير مفعّل"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"شريط التنقل"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"التنسيق"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"نوع زر اليسار الإضافي"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف.\nانقر للحصول على مزيد من المعلومات."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكن قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"الاطّلاع على خطوات العناية"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"فصل الشاحن"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"هناك مشكلة في شحن هذا الجهاز. يُرجى فصل محوِّل الطاقة بحرص لأن الكابل قد يكون ساخنًا."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"الاطّلاع على خطوات العناية"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"اختصار اليسار"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"اختصار اليمين"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 86f3a0e..912c82e 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"মুখাৱয়ব চিনিব নোৱাৰি"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ইয়াৰ সলনি ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযোগ হ’ল।"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"বেটাৰীৰ চাৰ্জৰ শতাংশ অজ্ঞাত।"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string>
@@ -300,7 +302,7 @@
     <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"অৱলোকন ট’গল কৰক"</string>
     <string name="zen_priority_introduction" msgid="3159291973383796646">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্ম, ৰিমাইণ্ডাৰ, ইভেন্ট আৰু কল কৰোঁতাৰ বাহিৰে আন কোনো শব্দৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
     <string name="zen_alarms_introduction" msgid="3987266042682300470">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্মৰ বাহিৰে আন কোনো ধ্বনি আৰু কম্পনৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
-    <string name="zen_priority_customize_button" msgid="4119213187257195047">"নিজৰ উপযোগিতা অনুসৰি"</string>
+    <string name="zen_priority_customize_button" msgid="4119213187257195047">"কাষ্টমাইজ কৰক"</string>
     <string name="zen_silence_introduction_voice" msgid="853573681302712348">"এই কার্যই এলার্ম, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আটাইবোৰৰ বাবে ধ্বনি আৰু কম্পন অৱৰোধ কৰিব। আপুনি ফ\'ন কল তথাপি কৰিবলৈ সক্ষম হ\'ব।"</string>
     <string name="zen_silence_introduction" msgid="6117517737057344014">"এই কার্যই এলার্ম, মিউজিক, ভিডিঅ\' আৰু গেইমকে ধৰি আটাইবোৰৰ ধ্বনি আৰু কম্পন অৱৰোধ কৰে।"</string>
     <string name="notification_tap_again" msgid="4477318164947497249">"খুলিবলৈ পুনৰাই টিপক"</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • দ্ৰুতগতিৰে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • লাহে লাহে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"কেপশ্বন অভাৰলে’"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"সক্ষম কৰক"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"অক্ষম কৰক"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ধ্বনি আৰু কম্পন"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ছেটিং"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"এপ্‌টো পিন কৰা আছে"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'পিছলৈ যাওক\' আৰু \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string>
@@ -529,7 +532,7 @@
     <string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জাননী নিয়ন্ত্ৰণসমূহ খোলা অৱস্থাত আছে"</string>
     <string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ জাননী নিয়ন্ত্ৰণসমূহ বন্ধ অৱস্থাত আছে"</string>
     <string name="notification_more_settings" msgid="4936228656989201793">"অধিক ছেটিং"</string>
-    <string name="notification_app_settings" msgid="8963648463858039377">"নিজৰ উপযোগিতা অনুসৰি"</string>
+    <string name="notification_app_settings" msgid="8963648463858039377">"কাষ্টমাইজ কৰক"</string>
     <string name="notification_conversation_bubble" msgid="2242180995373949022">"বাবল হিচাপে দেখুৱাওক"</string>
     <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Bubbles আঁতৰাওক"</string>
     <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"অন"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"অফ"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"উপলব্ধ নহয়"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"অক্ষম কৰা আছে"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"নেভিগেশ্বন দণ্ড"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"লেআউট"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"বাওঁ বুটামৰ অতিৰিক্ত প্ৰকাৰ"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ফ’নটো ঠাণ্ডা হৈ থকাৰ সময়ত কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"আপোনাৰ ফ\'নটোৱে নিজে নিজে ঠাণ্ডা হ\'বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ফ\'নটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nফ\'নটো সম্পূৰ্ণভাৱে ঠাণ্ডা হোৱাৰ পিছত ই আগৰ নিচিনাকৈয়েই চলিব।"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"চ্চার্জাৰ আনপ্লাগ কৰক"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"এই ডিভাইচটো চ্চার্জ কৰোঁতে কিবা সমস্যা হৈছে। পাৱাৰ এডাপ্টাৰটো আনপ্লাগ কৰক, কেব’লডাল গৰম হ’ব পাৰে গতিকে সাবধান হ’ব।"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"বাওঁ শ্বৰ্টকাট"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"সোঁ শ্বৰ্টকাট"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 1a02865..fd2d848 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Üzü tanımaq olmur"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmaq izi istifadə edin"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth qoşulub."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareyanın faizi naməlumdur."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtitr başlığı"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktiv edin"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiv edin"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Səs və vibrasiya"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ayarlar"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Tətbiq bərkidilib"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"\"Geri\" və \"Əsas ekran\" düymələrinin davamlı basılması ilə çıxarılana qədər tətbiq göz önündə qalır."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aktiv"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Deaktiv"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Əlçatan deyil"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Deaktiv edilib"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Naviqasiya paneli"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Tərtibat"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Əlavə sol düymə növü"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz avtomatik olaraq soyumağa başlayacaq. Telefon istifadəsinə davam edə bilərsiniz, lakin sürəti yavaşlaya bilər.\n\nTelefonunuz soyuduqdan sonra normal işləyəcək."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Adapteri cərəyandan ayırın"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu cihazın batareya yığmasında problem var. Adapteri cərəyandan ayırın. Ehtiyatlı olun, kabel isti ola bilər."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Sol qısayol"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Sağ qısayol"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 453a364..dbef1e4 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je priključen."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procenat napunjenosti baterije nije poznat."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Preklapanje titlova"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogućite"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogućite"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibriranje"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Podešavanja"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Pregled da biste ga otkačili."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Početna da biste ga otkačili."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Uključeno"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Isključeno"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nedostupno"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Onemogućeno"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Traka za navigaciju"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Raspored"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Dodatni tip levog dugmeta"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će automatski pokušati da se ohladi. I dalje ćete moći da koristite telefon, ali će sporije reagovati.\n\nKada se telefon ohladi, normalno će raditi."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte upozorenja"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Isključite punjač iz struje"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Došlo je do problema sa punjenjem ovog uređaja. Isključite adapter iz napajanja i budite pažljivi jer kabl može da bude topao."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upozorenja"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Leva prečica"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desna prečica"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index b35ddbe..372392c 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Твар не распазнаны"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скарыстайце адбітак пальца"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-сувязь."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Працэнт зараду акумулятара невядомы."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе хуткая зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе павольная зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Накладанне субцітраў"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"уключыць"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"адключыць"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Гук і вібрацыя"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Налады"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Праграма замацавана"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопкі \"Назад\" і \"Агляд\"."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, націсніце і ўтрымлівайце кнопкі \"Назад\" і \"Галоўны экран\"."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Уключана"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Выключана"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Недаступна"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Выключана"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Панэль навігацыі"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Раскладка"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Дадатковы тып кнопкі \"ўлева\""</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Некаторыя функцыі абмежаваны, пакуль тэлефон не астыне.\nНацісніце, каб даведацца больш"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш тэлефон аўтаматычна паспрабуе астыць. Вы можаце па-ранейшаму карыстацца сваім тэлефонам, але ён можа працаваць больш павольна.\n\nПасля таго як ваш тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Глядзець паэтапную дапамогу"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Адключыце зарадную прыладу"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Узнікла праблема з зарадкай гэтай прылады. Адключыце адаптар сілкавання і праверце, ці не нагрэўся кабель."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Глядзець паэтапную дапамогу"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ярлык \"улева\""</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Ярлык \"управа\""</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c2bb8ad..1bca6a4 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицето не е разпознато"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Използвайте отпечатък"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е включен."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентът на батерията е неизвестен."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Наслагване на надписите"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"активиране"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"деактивиране"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Звук и вибриране"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Настройки"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Приложението е фиксирано"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и „Начало“."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Вкл."</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Изкл."</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Не е налице"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Деактивирано"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Лента за навигация"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Оформление"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Тип на допълнителния ляв бутон"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Някои функции са ограничени, докато телефонът се охлажда.\nДокоснете за още информация"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонът ви автоматично ще направи опит за охлаждане. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Вижте стъпките, които да предприемете"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Изключете зарядното устройство"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"При зареждането на това устройство възникна проблем. Изключете захранващия адаптер и внимавайте, тъй като кабелът може да е топъл."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Вижте стъпките, които да предприемете"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ляв пряк път"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Десен пряк път"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 39435cd..80beebc 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ফেস শনাক্ত করা যায়নি"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"পরিবর্তে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ব্যাটারি কত শতাংশ আছে তা জানা যায়নি।"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ক্যাপশন ওভারলে"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"চালু হবে"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"বন্ধ হবে"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"সাউন্ড ও ভাইব্রেশন"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"সেটিংস"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"অ্যাপ পিন করা হয়েছে"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"ফিরে যান\" এবং \"হোম\" বোতামদুটি ট্যাপ করে ধরে রাখুন।"</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"চালু আছে"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"বন্ধ আছে"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"উপলভ্য নয়"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"বন্ধ করা আছে"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"আরও জানুন"</string>
     <string name="nav_bar" msgid="4642708685386136807">"নেভিগেশন বার"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"লেআউট"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"অতিরিক্ত বাঁদিকের বোতামের ধরণ"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ফোন ঠাণ্ডা না হওয়া পর্যন্ত কিছু ফিচার কাজ করে না।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"আপনার ফোনটি নিজে থেকেই ঠাণ্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠাণ্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"চার্জার আনপ্লাগ করুন"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"এই ডিভাইস চার্জ করার সময় সমস্যা হয়েছে। চার্জিং কেবলটি হয়ত গরম হয়ে গেছে, পাওয়ার অ্যাডাপ্টারটি আনপ্লাগ করুন।"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"কী করতে হবে ধাপে ধাপে দেখুন"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"বাঁদিকের শর্টকাট"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ডানদিকের শর্টকাট"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c60682f..ecb0e24 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Nije moguće prepoznati lice"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je povezan."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak napunjenosti baterije nije poznat"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Preklapanje titlova"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogući"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogući"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibracija"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Postavke"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Da otkačite ekran, dodirnite i držite dugme Nazad i Početna."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Uključeno"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Isključeno"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nedostupno"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Onemogućeno"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigaciona traka"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Raspored"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Vrsta dodatnog dugmeta lijevo"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon hladi.\nDodirnite za više informacija"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristi telefon, ali će možda raditi sporije.\n\nNakon što se ohladi, telefon će normalno raditi."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte korake za zaštitu"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Isključite punjač"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Došlo je do problema prilikom punjenja ovog uređaja. Pažljivo isključite adapter za napajanje jer je moguće da je kabl vruć."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Prikaz koraka za zaštitu"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Prečica lijevo"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Prečica desno"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 14e0cd5..bbffb02 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"No es reconeix la cara"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilitza l\'empremta digital"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connectat."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Es desconeix el percentatge de bateria."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposició de subtítols"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activar"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"So i vibració"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuració"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"L\'aplicació està fixada"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premudes els botons Enrere i Aplicacions recents."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, mantén premuts els botons Enrere i Inici."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activat"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desactivat"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Desactivat"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegació"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Disposició"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipus de botó addicional de l\'esquerra"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Algunes funcions estan limitades mentre el telèfon es refreda.\nToca per obtenir més informació"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Mostra els passos de manteniment"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconnecta el carregador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No es pot carregar el dispositiu. Desconnecta l\'adaptador de corrent amb compte, ja que el cable podria estar calent."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Mostra els pasos de manteniment"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Drecera de l\'esquerra"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Drecera de la dreta"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 25fa56f..66874fd 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Obličej nelze rozpoznat"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Použijte otisk prstu"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Rozhraní Bluetooth je připojeno."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procento baterie není známé."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Překryvná vrstva titulků"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivovat"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivovat"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Zvuk a vibrace"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavení"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikace je připnutá"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude připnut v zobrazení, dokud ho neuvolníte. Uvolníte ho podržením tlačítek Zpět a Plocha."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Zapnuto"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Vypnuto"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nedostupné"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Vypnuto"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigační panel"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Rozvržení"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Zvláštní typ tlačítka vlevo"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Některé funkce jsou při chladnutí telefonu omezeny.\nKlepnutím zobrazíte další informace"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobrazit pokyny, co dělat"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odpojte nabíječku"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Při nabíjení zařízení došlo k problému. Odpojte napájecí adaptér (dávejte pozor, kabel může být horký)."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobrazit pokyny, co dělat"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Zkratka vlevo"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Zkratka vpravo"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index a3a5488..ab201d7 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansigt kan ikke genkendes"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Brug fingeraftryk i stedet"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tilsluttet."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tilsluttet <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader hurtigt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader langsomt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlejrede undertekster"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivér"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Lyd og vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Indstillinger"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Til"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Fra"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ikke tilgængelig"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Deaktiveret"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigationslinje"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra venstre knaptype"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Nogle funktioner er begrænsede, mens telefonen køler ned.\nTryk for at få flere oplysninger"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Din telefon forsøger automatisk at køle ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se håndteringsvejledning"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Frakobl opladeren"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Der er et problem med opladning af denne enhed. Frakobl strømadapteren, og vær forsigtig, da kablet kan være varmt."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vejledningen i pleje"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Venstre genvej"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Højre genvej"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 3df0b43..5bf907c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Gesicht nicht erkannt"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Fingerabdruck verwenden"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Mit Bluetooth verbunden"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akkustand unbekannt."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string>
@@ -312,10 +314,8 @@
     <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Gerät mit dem Gesicht entsperrt. Tippe zum Öffnen."</string>
     <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Gesicht erkannt. Tippe zum Öffnen."</string>
     <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Gesicht erkannt. Tippe zum Öffnen auf das Symbol „Entsperren“."</string>
-    <!-- no translation found for keyguard_face_successful_unlock (4203999851465708287) -->
-    <skip />
-    <!-- no translation found for keyguard_face_successful_unlock_alt1 (5853906076353839628) -->
-    <skip />
+    <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"Gerät mit Gesicht entsperrt"</string>
+    <string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"Gesicht erkannt"</string>
   <string-array name="udfps_accessibility_touch_hints">
     <item msgid="1901953991150295169">"Nach links bewegen"</item>
     <item msgid="5558598599408514296">"Nach unten bewegen"</item>
@@ -341,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird schnell geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird langsam geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
@@ -422,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Untertitel-Overlay"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivieren"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivieren"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Ton &amp; Vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Einstellungen"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"App ist auf dem Bildschirm fixiert"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Startbildschirm\"."</string>
@@ -597,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"An"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Aus"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nicht verfügbar"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Deaktiviert"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigationsleiste"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Zusätzlicher linker Schaltflächentyp"</string>
@@ -670,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt.\nFür mehr Informationen tippen."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Dein Smartphone kühlt sich automatisch ab. Du kannst dein Smartphone weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Schritte zur Abkühlung des Geräts ansehen"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Ladegerät vom Stromnetz trennen"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Beim Laden dieses Geräts ist ein Problem aufgetreten. Trenne das Netzteil vom Stromnetz. Sei dabei vorsichtig, denn das Netzteil oder das Kabel könnte heiß sein."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Schritte zur Fehlerbehebung ansehen"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Linke Verknüpfung"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Rechte Verknüpfung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 16f8796..2a1403c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Αδύνατη η αναγν. προσώπου"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Χρησιμ. δακτυλ. αποτύπ."</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Το Bluetooth είναι συνδεδεμένο."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Άγνωστο ποσοστό μπαταρίας."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Επικάλυψη υπότιτλων"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ενεργοποίηση"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"απενεργοποίηση"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Ήχος και δόνηση"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ρυθμίσεις"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Η εφαρμογή είναι καρφιτσωμένη."</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Με αυτόν τον τρόπο παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα τα στοιχεία \"Επιστροφή\" και \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Με αυτόν τον τρόπο, παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα τα στοιχεία \"Πίσω\" και \"Αρχική οθόνη\" για ξεκαρφίτσωμα."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ενεργό"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Απενεργοποίηση"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Μη διαθέσιμο"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Ανενεργό"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Γραμμή πλοήγησης"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Διάταξη"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Επιπλέον τύπος αριστερού κουμπιού"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας.\nΠατήστε για περισσότερες πληροφορίες."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Το τηλέφωνό σας θα προσπαθήσει να μειώσει αυτόματα τη θερμοκρασία. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Δείτε βήματα αντιμετώπισης."</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Αποσυνδέστε τον φορτιστή"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Υπάρχει κάποιο πρόβλημα με τη φόρτιση αυτής της συσκευής. Αποσυνδέστε τον μετασχηματιστή με προσοχή, λαμβάνοντας υπόψη ότι το καλώδιο μπορεί να είναι ζεστό."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Δείτε βήματα αντιμετώπισης"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Αριστερή συντόμευση"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Δεξιά συντόμευση"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d9fea14..7b9c756 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 4378306..4e7d8a3 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d9fea14..7b9c756 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d9fea14..7b9c756 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Captions overlay"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"enable"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disable"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sound and vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Settings"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Unavailable"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Disabled"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"learn more"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra left button type"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Left shortcut"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Right shortcut"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index d1c353b..4262413 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎Can’t recognize face. Use fingerprint instead.‎‏‎‎‏‎"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎Can’t recognize face‎‏‎‎‏‎"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‎‎Use fingerprint instead‎‏‎‎‏‎"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎Bluetooth connected.‎‏‎‎‏‎"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎Battery percentage unknown.‎‏‎‎‏‎"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎Connected to ‎‏‎‎‏‏‎<xliff:g id="BLUETOOTH">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎Captions overlay‎‏‎‎‏‎"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎enable‎‏‎‎‏‎"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎disable‎‏‎‎‏‎"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎Sound &amp; vibration‎‏‎‎‏‎"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎Settings‎‏‎‎‏‎"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎App is pinned‎‏‎‎‏‎"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin.‎‏‎‎‏‎"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin.‎‏‎‎‏‎"</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎On‎‏‎‎‏‎"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎Off‎‏‎‎‏‎"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎Unavailable‎‏‎‎‏‎"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‎Disabled‎‏‎‎‏‎"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎learn more‎‏‎‎‏‎"</string>
     <string name="nav_bar" msgid="4642708685386136807">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎Navigation bar‎‏‎‎‏‎"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎Layout‎‏‎‎‏‎"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎Extra left button type‎‏‎‎‏‎"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎Some features limited while phone cools down.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap for more info‎‏‎‎‏‎"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎Your phone will automatically try to cool down. You can still use your phone, but it may run slower.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Once your phone has cooled down, it will run normally.‎‏‎‎‏‎"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎See care steps‎‏‎‎‏‎"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎Unplug charger‎‏‎‎‏‎"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎There’s an issue charging this device. Unplug the power adapter, and take care as the cable may be warm.‎‏‎‎‏‎"</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‏‎Unplug your device‎‏‎‎‏‎"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‎Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it, and take care as the cable may also be warm.‎‏‎‎‏‎"</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎See care steps‎‏‎‎‏‎"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎Left shortcut‎‏‎‎‏‎"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‏‏‏‎Right shortcut‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 97ddfd1..9a01ac8 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce el rostro"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella dactilar"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Se desconoce el porcentaje de la batería."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desactivados sí"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Eliminar todas las notificaciones"</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}many{# notificaciones más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"La pantalla está bloqueada en modo vertical."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Caja para postres"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activando…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos act."</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivos}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivos}other{# dispositivos}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Cámara en uso"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Datos móviles"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en el modo de invitado"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si agregas un usuario nuevo, se desactivará el modo de invitado y se borrarán todas las apps y los datos de la sesión de invitado actual."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzaste el límite de usuarios"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}other{Puedes agregar hasta # usuarios.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}many{Puedes agregar hasta # usuarios.}other{Puedes agregar hasta # usuarios.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"¿Confirmas que quieres quitar el usuario?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Se borrarán todas las aplicaciones y los datos de este usuario."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Quitar"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"habilitar"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inhabilitar"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sonido y vibración"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuración"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"La app está fijada"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones Atrás y Recientes."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones de inicio y Atrás."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Recuérdame"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Deshacer"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Posponer <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}other{# horas}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}many{# horas}other{# horas}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Ahorro de batería"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Inhabilitada"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Diseño"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón izquierdo adicional"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Algunas funciones se limitan durante el enfriamiento del teléfono.\nPresiona para obtener más información"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar correctamente."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconectar cargador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No se puede cargar el dispositivo. Desconecta el adaptador de la corriente con cuidado, ya que el cable podría estar caliente."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantenimiento"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Acceso directo izquierdo"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Acceso directo derecho"</string>
@@ -778,7 +785,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar o desactivar"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}other{Se agregaron # controles.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}many{Se agregaron # controles.}other{Se agregaron # controles.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Quitados"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Está en favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está en favoritos en la posición <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -935,7 +942,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar tarjeta"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar tarjeta"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está activa}other{# apps están activas}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está activa}many{# apps están activas}other{# apps están activas}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nueva información"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps activas"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas apps están activas y en ejecución, incluso mientras no las usas. Esto mejora su funcionalidad, pero también afecta la duración de batería."</string>
@@ -965,7 +972,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La cámara está desactivada"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"El micrófono está desactivado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están apagados"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitiendo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b2c29df..038c7b5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce la cara"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella digital"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentaje de batería desconocido."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desactivados"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Borrar todas las notificaciones"</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> más"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# notificación más en el grupo.}many{# notificaciones más en el grupo.}other{# notificaciones más en el grupo.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"La pantalla está bloqueada en modo vertical."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Caja para postres"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Compartir Internet"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activando…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos activado"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivos}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivos}other{# dispositivos}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Linterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Cámara en uso"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Datos móviles"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Estás en modo Invitado"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si añades un nuevo usuario, saldrás del modo Invitado y se eliminarán todas las aplicaciones y datos de la sesión de invitado actual."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Has alcanzado el límite de usuarios"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}other{Puedes añadir # usuarios como máximo.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Solo se puede crear un usuario.}many{Puedes añadir # usuarios como máximo.}other{Puedes añadir # usuarios como máximo.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"¿Quitar usuario?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Se eliminarán todas las aplicaciones y datos de este usuario."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Quitar"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activar"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sonido y vibración"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ajustes"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicación fijada"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"La aplicación se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La aplicación se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás e Inicio."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Recordar"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Deshacer"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Volverá a mostrarse en <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}other{# horas}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}many{# horas}other{# horas}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Ahorro de batería"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Inhabilitado"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Diseño"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón a la izquierda extra"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Se han limitado algunas funciones mientras el teléfono se enfría.\nToca para ver más información"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"El teléfono intentará enfriarse. Puedes seguir utilizándolo, pero es posible que funcione con mayor lentitud.\n\nUna vez que se haya enfriado, funcionará con normalidad."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecta el cargador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No se puede cargar el dispositivo. Desconecta el adaptador de corriente con cuidado, ya que el cable puede estar caliente."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantenimiento"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Acceso directo a la izquierda"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Acceso directo a la derecha"</string>
@@ -778,7 +785,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}other{# controles añadidos.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}many{# controles añadidos.}other{# controles añadidos.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Quitado"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Añadido a favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Añadido a favoritos (posición <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -935,7 +942,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Añadir recuadro"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No añadir recuadro"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuario"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicación activa}other{# aplicaciones activas}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicación activa}many{# aplicaciones activas}other{# aplicaciones activas}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Información nueva"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicaciones activas"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas aplicaciones están activas y en funcionamiento, incluso aunque no las estés usando. Esto mejora su funcionalidad, pero también puede afectar a la duración de la batería."</string>
@@ -965,7 +972,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La cámara está desactivada"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"El micrófono está desactivado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están desactivados"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificaciones}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiendo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 6b339f0..7317404 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Nägu ei õnnestu tuvastada"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kasutage sõrmejälge"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth on ühendatud."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Aku laetuse protsent on teadmata."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ühendatud: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kiirlaadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Aeglane laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtiitrite ülekate"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"luba"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"keela"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Heli ja vibreerimine"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Seaded"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Rakendus on kinnitatud"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Avakuva."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Sees"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Väljas"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Pole saadaval"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Keelatud"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigeerimisriba"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Paigutus"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Täiendava vasaku nupu tüüp"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Mõned funktsioonid on piiratud, kuni telefon jahtub.\nPuudutage lisateabe saamiseks."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vaadake hooldusjuhiseid"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Eemaldage laadija vooluvõrgust"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Selle seadme laadimisega on probleem. Eemaldage toiteadapter ja olge ettevaatlik, sest kaabel võib olla soe."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Vaadake hooldusjuhiseid"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Vasak otsetee"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Parem otsetee"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 024275a..a761098 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ezin da hauteman aurpegia. Erabili hatz-marka."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Ezin da ezagutu aurpegia"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Erabili hatz-marka"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-a konektatuta."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Bateriaren ehunekoa ezezaguna da."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Azpititulu gainjarriak"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"gaitu"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desgaitu"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Audioa eta dardara"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ezarpenak"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikazioa ainguratuta dago"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aktibatuta"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desaktibatuta"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ez dago erabilgarri"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Desgaituta"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"lortu informazio gehiago"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Nabigazio-barra"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Diseinua"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ezkerreko botoi gehigarriaren mota"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte.\nInformazio gehiago lortzeko, sakatu hau."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, telefonoa erabiltzen jarrai dezakezu, baina mantsoago funtziona lezake.\n\nTelefonoaren tenperatura jaitsi bezain laster, ohi bezala funtzionatzen jarraituko du."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ikusi zaintzeko urratsak"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Deskonektatu kargagailua"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Arazo bat izan da gailua kargatzean. Deskonektatu egokigailua eta kontuz ibili, kablea bero egon baitaiteke."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ikusi zaintzeko urratsak"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ezkerreko lasterbidea"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Eskuineko lasterbidea"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 5e68200..e7aefda 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"چهره شناسایی نشد"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"از اثر انگشت استفاده کنید"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوتوث متصل است."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"درصد شارژ باتری مشخص نیست."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"همپوشانی زیرنویس ناشنوایان"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"فعال کردن"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیرفعال کردن"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"صدا و لرزش"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"تنظیمات"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"برنامه سنجاق شده است"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"تا زمانی که سنجاق را برندارید، در نما نگه‌داشته می‌شود. برای برداشتن سنجاق، «برگشت» و «نمای کلی» را لمس کنید و نگه‌دارید."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"تا برداشتن سنجاق، در نما نگه‌داشته می‌شود. برای برداشتن سنجاق، «برگشت» و «صفحه اصلی» را لمس کنید و نگه‌دارید."</string>
@@ -550,8 +554,8 @@
     <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"مرکز"</string>
     <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>
     <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string>
-    <string name="keyboard_key_enter" msgid="8633362970109751646">"ورود"</string>
-    <string name="keyboard_key_backspace" msgid="4095278312039628074">"پس‌بر"</string>
+    <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string>
+    <string name="keyboard_key_backspace" msgid="4095278312039628074">"Backspace"</string>
     <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"پخش/مکث"</string>
     <string name="keyboard_key_media_stop" msgid="1509943745250377699">"متوقف کردن"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"بعدی"</string>
@@ -562,9 +566,9 @@
     <string name="keyboard_key_page_down" msgid="9035902490071829731">"صفحه قبل"</string>
     <string name="keyboard_key_forward_del" msgid="5325501825762733459">"حذف"</string>
     <string name="keyboard_key_move_home" msgid="3496502501803911971">"ابتدا"</string>
-    <string name="keyboard_key_move_end" msgid="99190401463834854">"انتها"</string>
-    <string name="keyboard_key_insert" msgid="4621692715704410493">"درج"</string>
-    <string name="keyboard_key_num_lock" msgid="7209960042043090548">"قفل اعداد"</string>
+    <string name="keyboard_key_move_end" msgid="99190401463834854">"End"</string>
+    <string name="keyboard_key_insert" msgid="4621692715704410493">"Insert"</string>
+    <string name="keyboard_key_num_lock" msgid="7209960042043090548">"Num Lock"</string>
     <string name="keyboard_key_numpad_template" msgid="7316338238459991821">"صفحه‌کلید عددی <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="notif_inline_reply_remove_attachment_description" msgid="7954075334095405429">"برداشتن پیوست"</string>
     <string name="keyboard_shortcut_group_system" msgid="1583416273777875970">"سیستم"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"روشن"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"خاموش"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"در دسترس نیست"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"غیرفعال"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"نوار پیمایش"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"طرح‌بندی"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"نوع دکمه منتهی‌الیه چپ"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"وقتی تلفن درحال خنک شدن است، بعضی از ویژگی‌ها محدود می‌شوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"تلفنتان به‌طور خودکار سعی می‌کند خنک شود. همچنان می‌توانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادی‌اش از سرگرفته می‌شود."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"دیدن اقدامات محافظتی"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"جدا کردن شارژر از برق"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"مشکلی در شارژ کردن این دستگاه وجود دارد. آداپتور برق را از برق جدا کنید و مراقب باشید زیرا ممکن است کابل گرم باشد."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"مشاهده مراحل احتیاط"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"میان‌بر چپ"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"میان‌بر راست"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 728f27d..21c8dfc 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Kasvoja ei voi tunnistaa"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Käytä sormenjälkeä"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth yhdistetty."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akun varaustaso ei tiedossa."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu nopeasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu hitaasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Tekstitysten peitto"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ota käyttöön"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"poista käytöstä"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Ääni ja värinä"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Asetukset"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Sovellus on kiinnitetty"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Aloitusnäyttö."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Päällä"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Pois päältä"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ei käytettävissä"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Ei käytössä"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigointipalkki"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Asettelu"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ylimääräinen vasen painiketyyppi"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana.\nLue lisää napauttamalla"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Katso huoltovaiheet"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Irrota laturi"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Laitetta ladattaessa tapahtui virhe. Irrota virtalähde varovasti – johto voi olla lämmin."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Katso huoltovaiheet"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Vasen pikakuvake"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Oikea pikakuvake"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3a7ff2a..b3439ae 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utiliser l\'empreinte digitale"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la pile inconnu."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Option « Capteurs désactivés » active"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Supprimer toutes les notifications"</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification à l\'intérieur.}one{# autre notification à l\'intérieur.}other{# autres notifications à l\'intérieur.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification à l\'intérieur.}one{# autre notification à l\'intérieur.}many{# d\'autres notifications à l\'intérieur.}other{# autres notifications à l\'intérieur.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"L\'écran est verrouillé en mode paysage."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"L\'écran est verrouillé en mode portrait."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Vitrine des desserts"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Point d\'accès sans fil"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activation en cours…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Écon. données activé"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}other{# appareils}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}many{# d\'appareils}other{# appareils}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampe de poche"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"L\'appareil photo est en cours d\'utilisation"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Données cellulaires"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un nouvel utilisateur, vous quitterez le mode Invité, et toutes les applications et données de la session d\'invité en cours seront supprimées."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite d\'utilisateurs atteinte"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter jusqu\'à # utilisateur.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter jusqu\'à # utilisateur.}many{Vous pouvez ajouter jusqu\'à # d\'utilisateurs.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Supprimer l\'utilisateur?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Supprimer"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposition de sous-titres"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Son et vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Paramètres"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Me rappeler"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Annuler"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Reporté pour <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}other{# heures}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}many{# d\'heures}other{# heures}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}many{# de minutes}other{# minutes}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Économiseur de pile"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Accueil"</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activé"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Désactivé"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Non disponible"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Désactivé"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"En savoir plus"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Barre de navigation"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Disposition"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Type de bouton gauche supplémentaire"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Certaines fonctionnalités sont limitées pendant que le téléphone refroidit.\nTouchez pour en savoir plus"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Débranchez le chargeur"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Il y a un problème avec la recharge de cet appareil. Débranchez l\'adaptateur d\'alimentation, et faites attention, car le câble pourrait être chaud."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Afficher les étapes d\'entretien"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Raccourci gauche"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Raccourci droit"</string>
@@ -751,38 +757,22 @@
     <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir la totalité de l\'écran"</string>
     <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Commutateur"</string>
-    <!-- no translation found for accessibility_allow_diagonal_scrolling (3258050349191496398) -->
-    <skip />
-    <!-- no translation found for accessibility_resize (5733759136600611551) -->
-    <skip />
-    <!-- no translation found for accessibility_change_magnification_type (666000085077432421) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_end_resizing (4881690585800302628) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_top_handle (2716851102182220718) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_left_handle (6694953733271752950) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_right_handle (9055988237319397605) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_bottom_handle (6531646968813821258) -->
-    <skip />
-    <!-- no translation found for accessibility_magnifier_size (3038755600030422334) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_zoom (4222088982642063979) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_medium (6994632616884562625) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_small (8144502090651099970) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_large (6602944330021308774) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_close (1099965835844673375) -->
-    <skip />
-    <!-- no translation found for accessibility_magnifier_edit (1522877239671820636) -->
-    <skip />
-    <!-- no translation found for accessibility_magnification_magnifier_window_settings (2834685072221468434) -->
-    <skip />
+    <string name="accessibility_allow_diagonal_scrolling" msgid="3258050349191496398">"Autoriser le défilement en diagonale"</string>
+    <string name="accessibility_resize" msgid="5733759136600611551">"Redimensionner"</string>
+    <string name="accessibility_change_magnification_type" msgid="666000085077432421">"Changer le type d\'agrandissement"</string>
+    <string name="accessibility_magnification_end_resizing" msgid="4881690585800302628">"Terminer le redimensionnement"</string>
+    <string name="accessibility_magnification_top_handle" msgid="2716851102182220718">"Poignée supérieure"</string>
+    <string name="accessibility_magnification_left_handle" msgid="6694953733271752950">"Poignée gauche"</string>
+    <string name="accessibility_magnification_right_handle" msgid="9055988237319397605">"Poignée droite"</string>
+    <string name="accessibility_magnification_bottom_handle" msgid="6531646968813821258">"Poignée inférieure"</string>
+    <string name="accessibility_magnifier_size" msgid="3038755600030422334">"Taille de loupe"</string>
+    <string name="accessibility_magnification_zoom" msgid="4222088982642063979">"Zoom"</string>
+    <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Moyenne"</string>
+    <string name="accessibility_magnification_small" msgid="8144502090651099970">"Petite"</string>
+    <string name="accessibility_magnification_large" msgid="6602944330021308774">"Grande"</string>
+    <string name="accessibility_magnification_close" msgid="1099965835844673375">"Fermer"</string>
+    <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Modifier"</string>
+    <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Paramètres de la fenêtre de loupe"</string>
     <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Touchez pour ouvrir fonction. d\'access. Personnalisez ou remplacez bouton dans Param.\n\n"<annotation id="link">"Afficher param."</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacez le bouton vers le bord pour le masquer temporairement"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string>
@@ -794,7 +784,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}other{# commandes ajoutées.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# de commandes ajoutées.}other{# commandes ajoutées.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -951,7 +941,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter de tuile"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}other{# applications sont actives}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}many{# d\'applications sont actives}other{# applications sont actives}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelle information"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applications actives"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applications sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
@@ -981,7 +971,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"L\'appareil photo est désactivé"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"Le micro est désactivé"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"L\'appareil photo et le micro sont désactivés"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# de notifications}other{# notifications}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion en cours…"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b718825..2ffb389 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilisez empreinte digit."</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la batterie inconnu."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Option \"Capteurs désactivés\" active"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Supprimer toutes les notifications"</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> autres"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification dans le groupe.}one{# autre notification dans le groupe.}other{# autres notifications dans le groupe.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# autre notification dans le groupe.}one{# autre notification dans le groupe.}many{# autres notifications dans le groupe.}other{# autres notifications dans le groupe.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"L\'écran est verrouillé en mode paysage."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"L\'écran est verrouillé en mode portrait."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Vitrine des desserts"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Point d\'accès"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activation…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Écon. données activé"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}other{# appareils}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# appareil}one{# appareil}many{# appareils}other{# appareils}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampe de poche"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Caméra en cours d\'utilisation"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Données mobiles"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Vous êtes en mode Invité"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Si vous ajoutez un utilisateur, le mode Invité sera désactivé et toutes les applis et les données de la session Invité actuelle seront supprimées."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite nombre utilisateurs atteinte"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter # utilisateur.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Vous ne pouvez créer qu\'un seul utilisateur.}one{Vous pouvez ajouter # utilisateur.}many{Vous pouvez ajouter jusqu\'à # utilisateurs.}other{Vous pouvez ajouter jusqu\'à # utilisateurs.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Supprimer l\'utilisateur ?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Supprimer"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sous-titres en superposition"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Son et vibreur"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Paramètres"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Elle restera visible jusqu\'à ce que vous la retiriez. Pour la retirer, appuyez de manière prolongée sur les boutons Retour et Aperçu."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Elle restera visible jusqu\'à ce que vous la retiriez. Pour la retirer, appuyez de manière prolongée sur les boutons Retour et Accueil."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"M\'envoyer un rappel"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Annuler"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Répétée après <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}other{# heures}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}other{# minutes}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# heure}=2{# heures}one{# heure}many{# heures}other{# heures}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minute}one{# minute}many{# minutes}other{# minutes}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Économiseur de batterie"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Bouton <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Accueil"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activé"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Désactivé"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponible"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Désactivé"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barre de navigation"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Disposition"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Type de bouton gauche supplémentaire"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Fonctionnalités limitées pendant le refroidissement du téléphone.\nAppuyer pour en savoir plus"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Débrancher le chargeur"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Un problème est survenu lors de la recharge de cet appareil. Débranchez l\'adaptateur secteur en faisant attention, car le câble risque d\'être chaud."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Afficher les étapes d\'entretien"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Raccourci gauche"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Raccourci droit"</string>
@@ -778,7 +785,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activer/désactiver"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}other{# commandes ajoutées.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# commandes ajoutées.}other{# commandes ajoutées.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -935,7 +942,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter le bloc"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter le bloc"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# appli est active}one{# appli est active}other{# applis sont actives}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# appli est active}one{# appli est active}many{# applis sont actives}other{# applis sont actives}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelles informations"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnement, mais peut également affecter l\'autonomie de la batterie."</string>
@@ -965,7 +972,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"Caméra désactivée"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"Micro désactivé"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Appareil photo et micro désactivés"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# notifications}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# notifications}other{# notifications}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion…"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e7905e8..2da351a 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Non se recoñeceu a cara"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa a impresión dixital"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Descoñécese a porcentaxe da batería."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando rapidamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Superposición de subtítulos"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activa"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactiva"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Son e vibración"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configuración"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"A aplicación está fixada"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"A pantalla manterase visible ata que deixes de fixala. Para facelo, mantén premido Atrás e Visión xeral."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"A pantalla manterase visible ata que deixes de fixala. Para facelo, mantén premido Atrás e Inicio."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Non dispoñible"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Desactivado"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Deseño"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón adicional á esquerda"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría.\nToca para obter máis información"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"O teléfono tentará arrefriar automaticamente. Podes utilizalo, pero é probable que funcione máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantemento"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecta o cargador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Produciuse un problema ao cargar este dispositivo. Desconecta o adaptador de corrente e ten coidado porque o cable pode estar quente."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantemento"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atallo á esquerda"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atallo á dereita"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 8123785..97fed23 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ચહેરો ઓળખાતો નથી"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"તો ફિંગરપ્રિન્ટ વાપરો"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"બ્લૂટૂથ કનેક્ટ થયું."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"બૅટરીની ટકાવારી અજાણ છે."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> થી કનેક્ટ થયાં."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"કૅપ્શન ઓવરલે"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ચાલુ કરો"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"બંધ કરો"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"સાઉન્ડ અને વાઇબ્રેશન"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"સેટિંગ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ઍપને પિન કરેલી છે"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને ઓવરવ્યૂને સ્પર્શ કરી રાખો."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને હોમને સ્પર્શ કરી રાખો."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ચાલુ"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"બંધ"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ઉપલબ્ધ નથી"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"બંધ છે"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"વધુ જાણો"</string>
     <string name="nav_bar" msgid="4642708685386136807">"નેવિગેશન બાર"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"લેઆઉટ"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"અતિરિક્ત ડાબો બટન પ્રકાર"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ફોન ઠંડો થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"તમારો ફોન ઑટોમૅટિક રીતે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"સારસંભાળના પગલાં જુઓ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ચાર્જરને અનપ્લગ કરો"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"આ ડિવાઇસને ચાર્જ કરવામાં કોઈ સમસ્યા છે. પાવર અડૅપ્ટર અનપ્લગ કરો અને કાળજી લેજો કદાચ કેબલ થોડો ગરમ થયો હોઈ શકે છે."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"સારસંભાળના પગલાં જુઓ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ડાબો શૉર્ટકટ"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"જમણો શૉર્ટકટ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 97ae5df..81a11b4 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरे की पहचान नहीं हुई"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"फ़िंगरप्रिंट इस्तेमाल करें"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट किया गया."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"इस बारे में जानकारी नहीं है कि अभी बैटरी कितने प्रतिशत चार्ज है."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"कैप्शन ऊपर लगाएं"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"चालू करें"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"आवाज़ और वाइब्रेशन"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिंग"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है, जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"चालू"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"बंद"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध नहीं है"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"बंद है"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"नेविगेशन बार"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"कुछ और बाएं बटन के प्रकार"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"फ़ोन के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अब भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिवाइस के रखरखाव के तरीके देखें"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर निकालें"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"इस डिवाइस को चार्ज करने में समस्या हुई. पावर अडैप्टर का प्लग निकालें. ऐसा करते समय सावधानी बरतें क्योंकि तार गर्म हो सकता है."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"प्रबंधन से जुड़े चरण देखें"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"बायां शॉर्टकट"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"दायां शॉर्टकट"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 5de94f1..7ef30b6 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Upotrijebite otisak prsta"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth povezan."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak baterije nije poznat."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Spojen na <xliff:g id="BLUETOOTH">%s</xliff:g> ."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sloj titlova"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogući"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogući"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Zvuk i vibracija"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Postavke"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je prikvačena"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Natrag i Pregled da biste ga otkvačili."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite gumbe Natrag i Početna i zadržite pritisak da biste ga otkvačili."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Uključeno"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Isključeno"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nedostupno"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Onemogućeno"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigacijska traka"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Izgled"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Vrsta dodatnog lijevog gumba"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke su značajke ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte upute za održavanje"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Iskopčajte punjač"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Pojavio se problem s punjenjem uređaja. Iskopčajte pretvarač napona i pazite jer se kabel može zagrijati."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upute za održavanje"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lijevi prečac"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desni prečac"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index efe27e5..b6bfc1b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Az arc nem ismerhető fel"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Használjon ujjlenyomatot"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth csatlakoztatva."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Az akkumulátor töltöttségi szintje ismeretlen."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Feliratok fedvény"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"engedélyezés"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"letiltás"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Hang és rezgés"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Beállítások"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Az alkalmazás ki van tűzve"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és a Kezdőképernyő elemet."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Be"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Ki"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nem használható"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Kikapcsolva"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigációs sáv"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Elrendezés"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"További bal oldali gombtípus"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Bizonyos funkciók korlátozottan működnek a telefon lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Olvassa el a kímélő használat lépéseit"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Húzza ki a töltőt"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Probléma adódott az eszköz töltése során. Húzza ki a hálózati adaptert. Vigyázzon, a kábel forró lehet."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Olvassa el a megfelelő használat lépéseit"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Bal oldali parancsikon"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Jobb oldali parancsikon"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 17c178a..0380303 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Դեմքը չի ճանաչվել"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Օգտագործեք մատնահետք"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-ը միացված է:"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Մարտկոցի լիցքի մակարդակն անհայտ է։"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Արագ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Դանդաղ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Ենթագրերի վրադրում"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"միացնել"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"անջատել"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Ձայն և թրթռոց"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Կարգավորումներ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Հավելվածն ամրացված է"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև չեղարկեք ամրացումը: Չեղարկելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Միացված է"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Անջատված է"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Հասանելի չէ"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Անջատված է"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Նավիգացիայի գոտի"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Դասավորություն"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Լրացուցիչ ձախ կոճակի տեսակ"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են։\nՀպեք՝ ավելին իմանալու համար։"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Անջատեք լիցքավորիչը հոսանքից"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Չհաջողվեց լիցքավորել սարքը: Անջատեք հոսանքի ադապտերը և ուշադիր եղեք՝ մալուխը կարող է տաքացած լինել:"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ձախ դյուրանցում"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Աջ դյուրանցում"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index e0f39b0..163dd9f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Tidak mengenali wajah"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan sidik jari"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlay teks"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktifkan"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"nonaktifkan"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Suara &amp; getaran"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Setelan"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikasi disematkan"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Kembali dan Ringkasan untuk melepas sematan."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ini akan terus ditampilkan sampai Anda melepas sematan. Sentuh lama tombol Kembali dan Beranda untuk melepas sematan."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aktif"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Nonaktif"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Tidak tersedia"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Nonaktif"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Bilah navigasi"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Tata Letak"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Jenis tombol ekstra kiri"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Beberapa fitur dibatasi saat ponsel mendingin.\nKetuk untuk info selengkapnya"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah-langkah perawatan"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Cabut pengisi daya"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ada masalah saat mengisi daya perangkat ini. Cabut adaptor daya dan berhati-hatilah karena kabelnya mungkin panas."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Lihat langkah-langkah perawatan"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Pintasan kiri"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Pintasan kanan"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 955c924..f2a0304 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Andlit þekkist ekki"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Nota fingrafar í staðinn"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tengt."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Staða rafhlöðu óþekkt."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tengt við <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Í hleðslu • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hraðhleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hæg hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Í hleðslu • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Yfirlögn myndatexta"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"virkja"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"slökkva"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Hljóð og titringur"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Stillingar"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Forrit er fest"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Til baka“ og „Yfirlit“ til að losa."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Þetta heldur þessu opnu þangað til það er losað. Haltu inni bakkhnappinum og heimahnappinum til að losa."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Kveikt"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Slökkt"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ekki í boði"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Slökkt"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Yfirlitsstika"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Útlit"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Gerð aukahnapps til vinstri"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Sumir eiginleikar eru takmarkaðir meðan síminn kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Síminn reynir sjálfkrafa að kæla sig. Þú getur enn notað símann en hann gæti verið hægvirkari.\n\nEftir að síminn hefur kælt sig niður virkar hann eðlilega."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sjá varúðarskref"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Taktu hleðslutækið úr sambandi"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Upp kom vandamál varðandi hleðslu tækisins. Taktu straumbreytinn úr sambandi og farðu varlega því snúran gæti verið heit."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Sjá varúðarskref"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Flýtilykill til vinstri"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Flýtilykill til hægri"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 73160c3..74f3e47 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Volto non riconosciuto"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa l\'impronta"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth collegato."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentuale della batteria sconosciuta."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connesso a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Opzione Sensori disattivati attiva"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Cancella tutte le notifiche."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# altra notifica nel gruppo.}other{Altre # notifiche nel gruppo.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{# altra notifica nel gruppo.}many{Altre # notifiche nel gruppo.}other{Altre # notifiche nel gruppo.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"Lo schermo è bloccato in orientamento orizzontale."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Lo schermo è bloccato in orientamento verticale."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Vetrina di dolci"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Attivazione…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Risp. dati attivo"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivi}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivi}other{# dispositivi}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Torcia"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Fotocamera in uso"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dati mobili"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Sei in modalità Ospite"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Se aggiungi un nuovo utente, la modalità Ospite viene disattivata e vengono eliminati tutti i dati e le app della sessione Ospite corrente."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Può essere creato un solo utente.}other{Puoi aggiungere fino a # utenti.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Può essere creato un solo utente.}many{Puoi aggiungere fino a # utenti.}other{Puoi aggiungere fino a # utenti.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Rimuovere l\'utente?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Tutte le app e i dati di questo utente verranno eliminati."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Rimuovi"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlay sottotitoli"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"attiva"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disattiva"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Suoni e vibrazione"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Impostazioni"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata sullo schermo"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Indietro e Home."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Ricordamelo"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Annulla"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Posticipato di <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# ora}=2{# ore}other{# ore}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minuti}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# ora}=2{# ore}many{# ore}other{# ore}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minuti}other{# minuti}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Risparmio energetico"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Pulsante <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Home page"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"On"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Off"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Non disponibile"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Riquadro disattivato"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra di navigazione"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo di pulsante extra sinistra"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Alcune funzionalità limitate durante il raffreddamento del telefono.\nTocca per ulteriori informazioni"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Il telefono cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il telefono funzionerà normalmente."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Leggi le misure da adottare"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Scollega il caricabatterie"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Si è verificato un problema durante la ricarica del dispositivo. Scollega l\'alimentatore e presta attenzione perché il cavo potrebbe essere caldo."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Leggi le misure da adottare"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Scorciatoia sinistra"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Scorciatoia destra"</string>
@@ -778,7 +785,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}other{# controlli aggiunti.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}many{# controlli aggiunti.}other{# controlli aggiunti.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Preferito, posizione <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -935,7 +942,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Aggiungi riquadro"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{C\'è # app attiva}other{Ci sono # app attive}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{C\'è # app attiva}many{Ci sono # app attive}other{Ci sono # app attive}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuove informazioni"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"App attive"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Queste app sono attive e in esecuzione, anche quando non le utilizzi. Questo migliora la loro funzionalità, ma influisce sulla durata della batteria."</string>
@@ -965,7 +972,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"La fotocamera è disattivata"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"Il microfono è disattivato"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotocamera e microfono non attivi"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}other{# notifiche}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}many{# notifiche}other{# notifiche}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Trasmissione in corso…"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e34987c..ac70efd 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"לא ניתן לזהות את הפנים"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"שימוש בטביעת אצבע במקום זאת"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"‏Bluetooth מחובר."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"אחוז טעינת הסוללה לא ידוע."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"התבצע חיבור אל <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"שכבת-על לכיתוב"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"הפעלה"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"השבתה"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"צליל ורטט"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"הגדרות"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"פועל"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"כבוי"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"לא זמין"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"מושבת"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"מידע נוסף"</string>
     <string name="nav_bar" msgid="4642708685386136807">"סרגל הניווט"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"פריסה"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"סוג נוסף של לחצן שמאלי"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"קירור הטלפון ייעשה באופן אוטומטי. ניתן עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"לצפייה בשלבי הטיפול"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"יש לנתק את המטען"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"יש בעיה עם הטעינה של המכשיר הזה. צריך לנתק את מתאם המתח בזהירות כי הכבל עלול להיות חם."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"ניתוק המכשיר"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"‏המכשיר שלך מתחמם בקרבת יציאת הטעינה. אם המכשיר מחובר למטען או לאביזר בחיבור USB, צריך לנתק אותו בזהירות כיוון שגם הכבל עלול להיות חם."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"לצפייה בשלבי הטיפול"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"קיצור דרך שמאלי"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"קיצור דרך ימני"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d471610..3fa66ef 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"顔を認識できません"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"指紋認証をお使いください"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetoothに接続済み。"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"バッテリー残量は不明です。"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>に接続しました。"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕のオーバーレイ"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"有効にする"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"無効にする"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"着信音とバイブレーション"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"アプリは固定されています"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [最近] を同時に押し続けると固定が解除されます。"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [ホーム] を同時に押し続けると固定が解除されます。"</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ON"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"OFF"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"使用不可"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"無効"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"詳細"</string>
     <string name="nav_bar" msgid="4642708685386136807">"ナビゲーション バー"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"レイアウト"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"その他の左ボタンタイプ"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"スマートフォンのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"取り扱いに関する手順をご覧ください"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"充電器を電源から外してください"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"このデバイスの充電中に問題が発生しました。電源アダプターを電源から外してください。ケーブルが熱くなっている可能性がありますのでご注意ください。"</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"デバイスを電源から外します"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"充電ポートの近くにデバイスを置くと、本体が熱くなります。デバイスが充電器や USB アクセサリに接続されている場合は外してください。ケーブルが熱くなっていることもあるので注意してください。"</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"取り扱いに関する手順をご覧ください"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"左ショートカット"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"右ショートカット"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 14e4141..4e0d5ce 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"სახის ამოცნობა შეუძლებ."</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"გამოიყენეთ თითის ანაბეჭდი"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth დაკავშირებულია."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ბატარეის პროცენტული მაჩვენებელი უცნობია."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"სუბტიტრების გადაფარვა"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ჩართვა"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"გამორთვა"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ხმა და ვიბრაცია"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"პარამეტრები"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"აპი ჩამაგრებულია"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან მთავარ გვერდზე“-ს."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ჩართული"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"გამორთვა"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"მიუწვდომელი"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"გათიშულია"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"ნავიგაციის ზოლი"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"განლაგება"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"მარცხენა დამატებითი ღილაკის ტიპი"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"მისაღები ზომების გაცნობა"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"გამოაერთეთ დამტენი"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ამ მოწყობილობის დატენა ვერ ხერხდება პრობლემის გამო. გამოაერთეთ ელკვების ადაპტერი და გამოიჩინეთ სიფრთხილე, რადგან კაბელი შეიძლებოდა გაცხელებულიყო."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"მისაღები ზომების გაცნობა"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"მარცხენა მალსახმობი"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"მარჯვენა მალსახმობი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 9d2f91a..10c47e3 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -161,6 +161,10 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <!-- no translation found for keyguard_face_failed (9044619102286917151) -->
+    <skip />
+    <!-- no translation found for keyguard_suggest_fingerprint (8742015961962702960) -->
+    <skip />
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth қосылған."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string>
@@ -339,8 +343,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Жылдам зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Баяу зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядталып жатыр. • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
@@ -420,6 +423,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Субтитр қою"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"қосу"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өшіру"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Дыбыс және діріл"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Параметрлер"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Қолданба бекітілді"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Өзіңіз босатқаша ашық тұрады. Босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Өзіңіз босатқаша ашық тұрады. Босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін басып тұрыңыз"</string>
@@ -595,7 +600,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Қосулы"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Өшірулі"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Қолжетімді емес"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Өшірілген"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Шарлау тақтасы"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Формат"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Қосымша сол жақ түйме түрі"</string>
@@ -668,8 +674,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі.\nТолығырақ ақпарат үшін түртіңіз."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nТелефон суығаннан кейін, оның жұмысы қалпына келеді."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Пайдалану нұсқаулығын қараңыз"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Зарядтағышты ажыратыңыз"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Құрылғыны зарядтау кезінде ақау шықты. Қуат адаптерін ажыратыңыз. Кабель ыстық болуы мүмкін, абай болыңыз."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Пайдалану нұсқаулығын қараңыз"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Сол жақ таңбаша"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Оң жақ таңбаша"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5aa9a53..7ee2a93 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"មិនអាចសម្គាល់មុខបានទេ"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ប្រើស្នាមម្រាមដៃជំនួសវិញ​"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"បាន​តភ្ជាប់​ប៊្លូធូស។"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"មិនដឹងអំពី​ភាគរយថ្មទេ។"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"បាន​ភ្ជាប់​ទៅ <xliff:g id="BLUETOOTH">%s</xliff:g> ។"</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុង​សាកថ្ម​យឺត • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរ​អ្នក​ប្រើ"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយ​ទាញចុះ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យ​ទាំងអស់​ក្នុង​វគ្គ​នេះ​នឹង​ត្រូវ​លុប។"</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ការដាក់ត្រួតគ្នា​លើអក្សររត់"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"បើក"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"បិទ"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"សំឡេង និងការញ័រ"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ការកំណត់"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"កម្មវិធី​ត្រូវបានខ្ទាស់"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​សង្កត់​ប៊ូតុង​ថយ​ក្រោយ និង​ប៊ូតុង​ទិដ្ឋភាពរួម​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុចប៊ូតុង​ថយក្រោយ និងប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"បើក"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"បិទ"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"មិនអាចប្រើបាន"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"បានបិទ"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"របាររុករក"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ប្លង់"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ប្រភេទ​ប៊ូតុង​ខាង​ឆ្វេង​បន្ថែម"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"មុខងារ​មួយចំនួន​នឹងមិនអាច​ប្រើបានពេញលេញ​នោះទេ ខណៈពេល​ដែលទូរសព្ទ​កំពុងបញ្ចុះកម្ដៅ។\nសូមចុច​ដើម្បីទទួលបាន​ព័ត៌មានបន្ថែម"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"ទូរសព្ទ​របស់អ្នក​នឹង​ព្យាយាម​បញ្ចុះ​កម្តៅ​ដោយ​ស្វ័យប្រវត្តិ។ អ្នក​នៅតែ​អាច​ប្រើ​ទូរសព្ទ​របស់អ្នក​បាន​ដដែល​ ប៉ុន្តែ​វា​នឹង​ដំណើរ​ការ​យឺត​ជាង​មុន។\n\nបន្ទាប់​ពី​ទូរសព្ទ​របស់អ្នក​ត្រជាក់​ជាង​មុន​ហើយ វា​នឹង​ដំណើរការ​ដូច​ធម្មតា។"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"មើលជំហាន​ថែទាំ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ផ្ដាច់ឆ្នាំងសាក"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"មាន​បញ្ហា​ក្នុងការសាកថ្ម​ឧបករណ៍​នេះ។ សូមផ្ដាច់​ឆ្នាំងសាក ហើយ​ប្រុងប្រយ័ត្ន ដោយសារ​ខ្សែ​អាចមាន​កម្ដៅ​ក្ដៅ។"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"មើលជំហាន​ថែទាំ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ផ្លូវកាត់​ខាង​ឆ្វេង"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ផ្លូវកាត់​ខាង​ស្តាំ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 15c17e46..2aec2e3 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ಬದಲಿಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ಬ್ಲೂಟೂತ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ಬ್ಯಾಟರಿ ಶೇಕಡಾವಾರು ತಿಳಿದಿಲ್ಲ."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ಶೀರ್ಷಿಕೆಗಳ ಓವರ್‌ಲೇ"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ಧ್ವನಿ &amp; ವೈಬ್ರೇಷನ್"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ಆ್ಯಪ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಮುಖಪುಟಕ್ಕೆ ಹಿಂತಿರುಗಿ."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ಆನ್"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ಆಫ್"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ಲಭ್ಯವಿಲ್ಲ"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ಲೇಔಟ್"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ಹೆಚ್ಚುವರಿ ಎಡ ಬಟನ್ ವಿಧ"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ, ಆದರೆ ಇದು ನಿಧಾನವಾಗಿರಬಹುದು.\n\nಒಮ್ಮೆ ನಿಮ್ಮ ಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ಚಾರ್ಜರ್ ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ಈ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡುತ್ತಿರುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ. ಪವರ್ ಅಡಾಪ್ಟರ್ ಅನ್ನು ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ ಮತ್ತು ಕೇಬಲ್ ಬೆಚ್ಚಗಿರಬೇಕೆಂದು ಜಾಗ್ರತೆ ವಹಿಸಿ."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ಕಾಳಜಿ ಹಂತಗಳನ್ನು ನೋಡಿ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ಎಡ ಶಾರ್ಟ್‌ಕಟ್"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ಬಲ ಶಾರ್ಟ್‌ಕಟ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4aed17f..b33d766 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"얼굴을 인식할 수 없습니다."</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"대신 지문을 사용하세요."</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"블루투스가 연결되었습니다."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"배터리 잔량을 알 수 없습니다."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string>
@@ -281,7 +283,7 @@
     <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"시작"</string>
     <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"중지"</string>
     <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string>
-    <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 차단 해제하시겠습니까?"</string>
+    <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 &amp;#173;차단 해제하시겠습니까?"</string>
     <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"기기 카메라를 차단 해제하시겠습니까?"</string>
     <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"기기 카메라 및 마이크를 차단 해제하시겠습니까?"</string>
     <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"마이크를 사용할 수 있는 모든 앱 및 서비스에 대해 액세스가 차단 해제됩니다."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"캡션 오버레이"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"사용"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"사용 중지"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"소리 및 진동"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"설정"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"앱 고정됨"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 홈을 길게 터치하세요."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"사용"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"사용 안함"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"사용할 수 없음"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"사용 안함"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"탐색 메뉴"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"레이아웃"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"추가 왼쪽 버튼 유형"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"휴대전화 온도를 자동으로 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"해결 방법 확인하기"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"충전기를 연결 해제하세요"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"기기를 충전하는 중에 문제가 발생했습니다. 케이블이 뜨거울 수 있으므로 주의하여 전원 어댑터를 분리하세요."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"취해야 할 조치 확인"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"왼쪽 바로가기"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"오른쪽 바로가기"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index cf196bc..b352277 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Жүз таанылбай жатат"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Манжа изин колдонуңуз"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth байланышта"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея кубатынын деңгээли белгисиз."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Коштомо жазуулардын үстүнө коюу"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"иштетүү"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өчүрүү"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Үн жана дирилдөө"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Параметрлер"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Колдонмо кадалды"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн \"Артка\" жана \"Назар\" баскычтарын басып, кармап туруңуз."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Күйүк"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Өчүк"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Жеткиликсиз"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Өчүрүлгөн"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Чабыттоо тилкеси"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Калып"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Сол жактагы кошумча баскычтын түрү"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Тейлөө кадамдарын көрүңүз"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Кубаттагычты сууруңуз"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Бул түзмөктү кубаттоодо маселе келип чыкты. Кабель ысып кетиши мүмкүн, андыктан кубаттагыч адаптерин сууруп коюңуз."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Тейлөө кадамдарын көрүңүз"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Сол жактагы кыска жол"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Оң жактагы кыска жол"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index ed5d3f7..f90e869 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ບໍ່ຮູ້ເປີເຊັນແບັດເຕີຣີ."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມ​ຕໍ່​ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ຄຳບັນຍາຍແບບວາງທັບ"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ເປີດນຳໃຊ້"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ປິດນຳໃຊ້"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ສຽງ ແລະ ການສັ່ນເຕືອນ"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ການຕັ້ງຄ່າ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ແອັບຖືກປັກໝຸດແລ້ວ"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກໝຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກໝຸດ."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ເປີດ"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ປິດ"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ບໍ່ສາມາດໃຊ້ໄດ້"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ປິດການນຳໃຊ້ແລ້ວ"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"ແຖບນຳທາງ"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ຮູບແບບ"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ປະເພດປຸ່ມຊ້າຍພິເສດ"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມລົດອຸນຫະພູມລົງ. ທ່ານຍັງຄົງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ມັນຈະເຮັດວຽກຊ້າລົງ.\n\nເມື່ອໂທລະສັບຂອງທ່ານບໍ່ຮ້ອນຫຼາຍແລ້ວ, ມັນຈະກັບມາເຮັດວຽກຕາມປົກກະຕິ."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ຖອດສາຍສາກອອກ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ເກີດບັນຫາໃນການສາກໄຟອຸປະກອນນີ້. ກະລຸນາຖອດສາຍສາກອອກ ແລະ ລະວັງເນື່ອງຈາກສາຍອາດຈະຍັງອຸ່ນຢູ່."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ປຸ່ມລັດຊ້າຍ"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ປຸ່ມລັດຂວາ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c535108..fdf4570 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Veidas neatpažintas"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Naudoti piršto antspaudą"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"„Bluetooth“ prijungtas."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumuliatoriaus energija procentais nežinoma."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Prisijungta prie „<xliff:g id="BLUETOOTH">%s</xliff:g>“."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtitrų perdanga"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"įgalinti"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"išjungti"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Garsas ir vibravimas"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nustatymai"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Programa prisegta"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Pagrindinis ekranas“, kad atsegtumėte."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Įjungta"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Išjungta"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nepasiekiama"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Išjungta"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Naršymo juosta"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Išdėstymas"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Papildomo mygtuko kairėje tipas"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta.\nPalietę gausite daugiau informacijos"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Žr. priežiūros veiksmus"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Atjunkite kroviklį"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Įkraunant šį įrenginį iškilo problema. Atjunkite maitinimo adapterį. Būkite atsargūs, nes laidas gali būti įkaitęs."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Žr. priežiūros veiksmus"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Spartusis klavišas kairėje"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Spartusis klavišas dešinėje"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 834cf77..9ca7da5 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Nevar atpazīt seju"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Lietot pirksta nospiedumu"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth savienojums ir izveidots."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumulatora uzlādes līmenis procentos nav zināms."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ātrā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lēnā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Subtitri pārklājas"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"iespējot"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"atspējot"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Skaņa un vibrācija"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Iestatījumi"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Lietotne ir piesprausta"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām Atpakaļ un Pārskats un turiet tās."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām “Atpakaļ” un “Sākums” un turiet tās."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ieslēgts"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Izslēgts"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nav pieejams"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Atspējots"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigācijas josla"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Izkārtojums"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Kreisās puses papildu pogas veids"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Dažas funkcijas ir ierobežotas, kamēr notiek tālruņa atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Skatīt apkopes norādījumus"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Lādētāja atvienošana"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Uzlādējot šo ierīci, radās problēma. Atvienojiet strāvas adapteri. Esiet uzmanīgs — vads var būt uzsilis."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Skatīt apkopes norādījumus"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Saīsne kreisajā pusē"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Saīsne labajā pusē"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 523ae5d..a241e54 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Не се препознава ликот"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користи отпечаток"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е поврзан."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентот на батеријата е непознат."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни брзо • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни бавно • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Преклопување титли"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"овозможи"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрации"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Поставки"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е закачена"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string>
@@ -595,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Вклучено"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Исклучено"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Недостапно"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Оневозможено"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"дознајте повеќе"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Лента за навигација"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Распоред"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Тип дополнително лево копче"</string>
@@ -668,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Некои функции се ограничени додека телефонот се лади.\nДопрете за повеќе информации"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонот автоматски ќе се обиде да се олади. Вие сепак ќе може да го користите, но тој може да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Прикажи ги чекорите за грижа за уредот"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Исклучете го полначот"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Има проблем со полнењето на уредов. Исклучете го адаптерот за напојување и внимавајте зошто кабелот може да е топол."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Прикажи ги чекорите за грижа за уредот"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Лева кратенка"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Десна кратенка"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 26a47de..4ff23018 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"മുഖം തിരിച്ചറിയാനാകുന്നില്ല"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്തു."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ബാറ്ററി ശതമാനം അജ്ഞാതമാണ്."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> എന്നതിലേക്ക് കണക്‌റ്റുചെയ്‌തു."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"അടിക്കുറിപ്പുകൾ മുകളിൽ വയ്ക്കുക"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ശബ്‌ദവും വൈബ്രേഷനും"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ക്രമീകരണം"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ആപ്പ് പിൻ ചെയ്തു"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ പോവുക\', \'ഹോം\' ബട്ടണുകൾ സ്‌പർശിച്ച് പിടിക്കുക."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ഓൺ"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ഓഫ്"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ലഭ്യമല്ല"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"പ്രവർത്തനരഹിതമാക്കി"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"നാവിഗേഷൻ ബാർ"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ലേ‌ഔട്ട്"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"അധിക ഇടത് ബട്ടൺ തരം"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തപ്പെടും.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കും.\n\nതണുത്തുകഴിഞ്ഞാൽ, ഫോൺ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കും."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ചാർജർ അൺപ്ലഗ് ചെയ്യുക"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ഈ ഉപകരണം ചാർജ് ചെയ്യുന്നതിൽ തടസ്സമുണ്ട്. പവർ അഡാപ്റ്റർ അൺപ്ലഗ് ചെയ്യുക, കേബിളിന് ചൂടുണ്ടായിരിക്കുമെന്നതിനാൽ ശ്രദ്ധിക്കണം."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"മുൻകരുതൽ നടപടികൾ കാണുക"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ഇടത് കുറുക്കുവഴി"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"വലത് കുറുക്കുവഴി"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0f01c7a..a3d13bd 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Царайг танихгүй байна"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Оронд нь хурууны хээ ашиглах"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth холбогдсон."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарейн хувь тодорхойгүй байна."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Давхарласан хадмал"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"идэвхжүүлэх"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"идэвхгүй болгох"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Дуу, чичиргээ"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Тохиргоо"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Аппыг бэхэлсэн"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулна. Тогтоосныг болиулахын тулд Буцах, Тоймыг дараад хүлээнэ үү."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Буцах, Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Идэвхтэй"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Идэвхгүй"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Боломжгүй"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Идэвхгүй болгосон"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"нэмэлт мэдээлэл авах"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Навигацын самбар"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Бүдүүвч"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Нэмэлт зүүн товчлуураар шивэх"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Утсыг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Таны утас автоматаар хөрөх болно. Та утсаа ашиглаж болох хэдий ч удаан ажиллаж болзошгүй.\n\nТаны утас хөрсний дараагаар хэвийн ажиллана."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Хянамж болгоомжийн алхмыг харах"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Цэнэглэгчийг салгана уу"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Энэ төхөөрөмжийг цэнэглэхэд асуудал гарлаа. Тэжээлийн залгуурыг салгана уу. Кабель халсан байж болзошгүй тул болгоомжтой байгаарай."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Хянамж болгоомжийн алхмыг харна уу"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Зүүн товчлол"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Баруун товчлол"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 167ad7b..c9f3bc2 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरा ओळखू शकत नाही"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"त्याऐवजी फिंगरप्रिंट वापरा"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्‍ट केले."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"बॅटरीच्या चार्जिंगची टक्केवारी माहित नाही."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्‍ट केले."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"कॅप्शन ओव्हरले करा"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"सुरू करा"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करा"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"आवाज आणि व्हायब्रेशन"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिंग्ज"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ॲप पिन केले आहे"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"तुम्ही अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तुम्ही अनपिन करेर्यंत हे त्याला दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी मागे आणि होम वर स्पर्श करा आणि धरून ठेवा."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"सुरू"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"बंद"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध नाही"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"बंद केली"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"नॅव्हिगेशन बार"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"अतिरिक्त डाव्या बटणाचा प्रकार"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"फोन थंड होईपर्यंत काही वैशिष्ट्ये मर्यादित केली.\nअधिक माहितीसाठी टॅप करा"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पहा"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग करा"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"हे डिव्हाइस चार्ज करताना समस्या आहे. पॉवर अडॅप्टर अनप्लग करा आणि शक्य तेवढी काळजी घ्या कदाचित केबल गरम असू शकते."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"काय काळजी घ्यावी ते पहा"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"डावा शॉर्टकट"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"उजवा शॉर्टकट"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 5e1c517d..b161345 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Tak dapat mengecam wajah"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan cap jari"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth disambungkan."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Peratusan kuasa bateri tidak diketahui."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Disambungkan kepada <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Tindanan kapsyen"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"dayakan"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"lumpuhkan"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Bunyi &amp; getaran"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Tetapan"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Apl telah disemat"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Ikhtisar untuk menyahsemat."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Skrin Utama untuk menyahsemat."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Hidup"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Mati"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Tidak tersedia"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Dilumpuhkan"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Bar navigasi"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Reka letak"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Jenis butang kiri tambahan"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Sesetengah ciri adalah terhad semasa telefon menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah penjagaan"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Cabut palam pengejas"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Terdapat isu semasa mengecas peranti ini. Cabut palam penyesuai kuasa. Berhati-hati kerana kabel mungkin hangat."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Lihat langkah penjagaan"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Pintasan kiri"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Pintasan kanan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e7ddf68..3f201ac3 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"မျက်နှာကို မမှတ်မိပါ"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"လက်ဗွေကို အစားထိုးသုံးပါ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ဘက်ထရီရာခိုင်နှုန်းကို မသိပါ။"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"စာတန်းများ ထပ်ပိုးရန်"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ဖွင့်ရန်"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ပိတ်ရန်"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"အသံနှင့် တုန်ခါမှု"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ဆက်တင်များ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးထားသည်"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"သင်က ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို တို့၍ဖိထားပါ။"</string>
@@ -569,7 +573,7 @@
     <string name="notif_inline_reply_remove_attachment_description" msgid="7954075334095405429">"ပူးတွဲပါဖိုင်ကို ဖယ်ရှားရန်"</string>
     <string name="keyboard_shortcut_group_system" msgid="1583416273777875970">"စနစ်"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="7465138628692109907">"ပင်မ"</string>
-    <string name="keyboard_shortcut_group_system_recents" msgid="8628108256824616927">"လတ်တလော"</string>
+    <string name="keyboard_shortcut_group_system_recents" msgid="8628108256824616927">"မကြာသေးမီက"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="1055709713218453863">"နောက်သို့"</string>
     <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"အကြောင်းကြားချက်များ"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ဖွင့်"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ပိတ်"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"မရနိုင်ပါ"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ပိတ်ထားသည်"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"ရွှေ့လျားရန်ဘားတန်း"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"အပြင်အဆင်"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"လက်ဝဲခလုတ် အမျိုးအစားအပို"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါလိမ့်မည်။ ဖုန်းကို အသုံးပြုနိုင်ပါသေးသည် သို့သော် ပိုနှေးနိုင်ပါသည်။\n\nသင့်ဖုန်း အေးသွားသည်နှင့် ပုံမှန်အတိုင်း ပြန်အလုပ်လုပ်ပါလိမ့်မည်။"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"အားသွင်းကိရိယာ ပလပ်ဖြုတ်ပါ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ဤစက်ပစ္စည်းကို အားသွင်းရာတွင် ပြဿနာရှိနေသည်။ ပါဝါ ကြားခံကိရိယာကို ပလပ်ဖြုတ်ပါ။ ကေဘယ်ကြိုး ပူနွေးနေနိုင်သဖြင့် သတိထားပါ။"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"လက်ဝဲ ဖြတ်လမ်းလင့်ခ်"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"လက်ယာ ဖြတ်လမ်းလင့်ခ်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8395694..24dcef7 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet gjenkjennes ikke"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bruk fingeravtrykk"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth er tilkoblet."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriprosenten er ukjent."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlegg med teksting"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivér"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Lyd og vibrering"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Innstillinger"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er festet"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Gjør at den vises til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Gjør at den vises til du løsner den. Trykk og hold inne Tilbake og Startside for å løsne den."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"På"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Av"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Utilgjengelig"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Slått av"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigasjonsrad"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Oppsett"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra venstre-knapptype"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Enkelte funksjoner er begrenset mens telefonen kjøles ned.\nTrykk for å se mer informasjon"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonen din kommer til å prøve å kjøle seg ned automatisk. Du kan fremdeles bruke telefonen, men den kjører muligens saktere.\n\nTelefonen kommer til å kjøre som normalt, når den har kjølt seg ned."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se vedlikeholdstrinnene"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Koble fra laderen"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Det oppsto et problem med lading av enheten. Koble fra strømadapteren, og vær forsiktig, kabelen kan være varm."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vedlikeholdstrinnene"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Venstre hurtigtast"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Høyre hurtigtast"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 8e97af9..4f85e3e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"अनुहार पहिचान गर्न सकिएन"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ब्याट्रीमा कति प्रतिशत चार्ज छ भन्ने कुराको जानाकरी छैन।"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"क्याप्सनको ओभरले"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"सक्षम पार्नुहोस्"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"असक्षम पार्नुहोस्"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"साउन्ड तथा भाइब्रेसन"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"सेटिङ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"एप पिन गरिएको छ"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई टच एण्ड होल्ड गर्नुहोस्।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई टच एण्ड होल्ड गर्नुहोस्।"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"अन छ"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"अफ छ"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"उपलब्ध छैन"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"अफ गरियो"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"नेभिगेशन पट्टी"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"लेआउट"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"अतिरिक्त बायाँतिरको बटनको प्रकार"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"फोन नचिस्सिँदासम्म केही सुविधाहरू उपलब्ध हुने छैनन्।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"तपाईंको फोन स्वतः चिसो हुने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो फोनको प्रयोग गर्न सक्नुहुन्छ तर त्यो अझ ढिलो चल्न सक्छ।\n\nचिसो भएपछि तपाईंको फोन सामान्य गतिमा चल्नेछ।"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग गर्नुहोस्‌"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"यो डिभाइस चार्ज गर्दा कुनै समस्या भयो। पावर एडाप्टर अनप्लग गर्नुहोस्‌ र केबल तातो हुन सक्ने भएकाले ध्यान दिनुहोस्‌।"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"हेरचाहसम्बन्धी चरणहरू हेर्नुहोस्‌"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"बायाँतिरको सर्टकट"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"दायाँतिरको सर्टकट"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ea86522..ee08b01 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Gezicht niet herkend"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Vingerafdruk gebruiken"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-verbinding ingesteld."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterijpercentage onbekend."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Verbonden met <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Ondertitelingsoverlay"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aanzetten"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"uitzetten"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Geluid en trillen"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Instellingen"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is vastgezet"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Home en houd deze vast om het scherm los te maken."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Uit"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Niet beschikbaar"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Uitgezet"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"meer informatie"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigatiebalk"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Lay-out"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra knoptype links"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt.\nTik voor meer informatie"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Onderhoudsstappen bekijken"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Oplader loskoppelen"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Er is een probleem met het opladen van dit apparaat. Koppel de voedingsadapter los. Wees voorzichtig, want de kabel kan warm zijn."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Onderhoudsstappen bekijken"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Snelkoppeling links"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Snelkoppeling rechts"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 31929c5..6923145 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ଫେସ ଚିହ୍ନଟ ହୋଇପାରିବ ନାହିଁ"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ବ୍ଲୁଟୂଥ୍‍‌ ସଂଯୋଗ କରାଯାଇଛି।"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଅଜଣା ଅଟେ।"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"କ୍ୟାପ୍ସନ୍‌ର ଓଭର୍‌ଲେ"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ଅକ୍ଷମ କରନ୍ତୁ"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେସନ"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ସେଟିଂସ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍ କରିବା ପାଇଁ ହୋମ ଓ ବ୍ୟାକ ବଟନକୁ ଦବାଇ ଧରନ୍ତୁ।"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ଚାଲୁ ଅଛି"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ବନ୍ଦ ଅଛି"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ଅନୁପଲବ୍ଧ"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ଅକ୍ଷମ କରାଯାଇଛି"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"ନାଭିଗେଶନ୍ ବାର୍‍"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ଲେଆଉଟ୍"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ସମ୍ପୂର୍ଣ୍ଣ ବାମ ବଟନ୍‍ ପ୍ରକାର"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ଫୋନ୍ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର୍ ଠିକ ଭାବେ କାମ କରିନଥାଏ।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"ଆପଣଙ୍କ ଫୋନ୍‍ ସ୍ୱଚାଳିତ ଭାବେ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ତଥାପି ନିଜ ଫୋନ୍‍ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଫୋନ୍‍ ଥଣ୍ଡା ହୋଇଯିବାପରେ, ଏହା ସାମାନ୍ୟ ଭାବେ ଚାଲିବ।"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ଚାର୍ଜର୍‍ ଅନ୍‍ପ୍ଲଗ୍‌ କରନ୍ତୁ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ଏହି ଡିଭାଇସ୍ ଚାର୍ଜ କରିବାରେ ଗୋଟିଏ ସମସ୍ୟା ଅଛି। ଯେହେତୁ କେବଳ ଗରମ ହୋଇଯାଇପାରେ, ତେଣୁ ପାୱାର୍ ଆଡପ୍ଟର୍ ଅନ୍‌ପ୍ଲଗ୍‌ କରନ୍ତୁ ଏବଂ ଯତ୍ନ ନିଅନ୍ତୁ।"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ସେବା ସମ୍ବନ୍ଧିତ ଷ୍ଟେପ୍‌ଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ବାମ ଶର୍ଟକଟ୍‍"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ଡାହାଣ ଶର୍ଟକଟ୍‍"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 1374121..2beeb59 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ਬੈਟਰੀ ਪ੍ਰਤੀਸ਼ਤ ਅਗਿਆਤ ਹੈ।"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ।"</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"ਸੁਰਖੀਆਂ ਓਵਰਲੇ"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ਚਾਲੂ ਕਰੋ"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ਬੰਦ ਕਰੋ"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ਧੁਨੀ ਅਤੇ ਥਰਥਰਾਹਟ"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ਐਪ ਨੂੰ ਪਿੰਨ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਅਨਪਿੰਨ ਕੀਤੇ ਜਾਣ ਤੱਕ ਇਸਨੂੰ ਦਿਖਾਇਆ ਜਾਂਦਾ ਹੈ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਹੋਮ\' ਨੂੰ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ਚਾਲੂ"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ਬੰਦ"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ਅਣਉਪਲਬਧ"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ਬੰਦ ਹੈ"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"ਨੈਵੀਗੇਸ਼ਨ ਵਾਲੀ ਪੱਟੀ"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ਖਾਕਾ"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ਵਧੇਰੇ ਖੱਬੇ ਬਟਨ ਕਿਸਮ"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਤ ਹੁੰਦੀਆਂ ਹਨ।\nਵਧੇਰੇ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਵੈਚਲਿਤ ਰੂਪ ਵਿੱਚ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰੰਤੂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਵਧੇਰੇ ਹੌਲੀ ਚੱਲੇ।\n\nਇੱਕ ਵਾਰ ਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਧਾਰਨ ਤੌਰ \'ਤੇ ਚੱਲੇਗਾ।"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ਚਾਰਜਰ ਨੂੰ ਕੱਢੋ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਚਾਰਜ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆ ਗਈ ਹੈ। ਪਾਵਰ ਅਡਾਪਟਰ ਨੂੰ ਕੱਢੋ ਅਤੇ ਧਿਆਨ ਰੱਖੋ ਸ਼ਾਇਦ ਕੇਬਲ ਗਰਮ ਹੋਵੇ।"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ਖੱਬਾ ਸ਼ਾਰਟਕੱਟ"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ਸੱਜਾ ਸ਼ਾਰਟਕੱਟ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index dafa699..9449f26 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Nie można rozpoznać twarzy"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Użyj odcisku palca"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth połączony."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Poziom naładowania baterii jest nieznany."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,11 +341,9 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Szybkie ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wolne ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
-    <!-- no translation found for accessibility_multi_user_list_switcher (8574105376229857407) -->
-    <skip />
+    <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
     <string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
@@ -421,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Nakładka z napisami"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"włącz"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"wyłącz"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Dźwięk i wibracje"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ustawienia"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacja jest przypięta"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Wstecz oraz Ekran główny."</string>
@@ -596,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Włączono"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Wyłączono"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Niedostępne"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Wyłączono"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Pasek nawigacji"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Układ"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Typ dodatkowego lewego przycisku"</string>
@@ -669,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone\nKliknij, by dowiedzieć się więcej"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale telefon może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działał normalnie."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobacz instrukcję postępowania"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odłącz ładowarkę"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Podczas ładowania tego urządzenia wystąpił błąd. Odłącz zasilacz, zwracając uwagę na kabel, który może być gorący."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobacz instrukcję postępowania"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lewy skrót"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Prawy skrót"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 59aee9b..2f9a36e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opção \"Sensores desativados\" está ativa"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}other{Mais # notificações no grupo.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}many{Mais # de notificações no grupo.}other{Mais # notificações no grupo.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"A tela está bloqueada na orientação paisagem."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"A tela está bloqueada na orientação retrato."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Mostruário de sobremesas"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Ponto de acesso"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Ativando…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Economia de dados ativada"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}other{# dispositivos}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}many{# de dispositivos}other{# dispositivos}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmera em uso"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dados móveis"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Você está no modo visitante"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo usuário, o dispositivo vai sair do modo visitante e excluir todos os apps e dados da Sessão de visitante atual."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}other{Você pode adicionar até # usuários.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}many{Você pode adicionar até # de usuários.}other{Você pode adicionar até # usuários.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Remover usuário?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Todos os apps e dados deste usuário serão excluídos."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sobreposição de legendas"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ativar"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configurações"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Lembrete"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Desfazer"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}other{# horas}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}other{# minuto}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}many{# de horas}other{# horas}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}many{# de minutos}other{# minuto}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Economia de bateria"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo extra"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecte o carregador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema com o carregamento deste dispositivo. Desconecte o adaptador de energia com cuidado, já que o cabo pode estar quente."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver etapas de cuidado"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atalho à esquerda"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atalho à direita"</string>
@@ -778,7 +785,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}other{# controles adicionados.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -935,7 +942,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}other{# apps estão ativos}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
@@ -965,7 +972,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"A câmera está desativada"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"O microfone está desativado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}many{# notificações}other{# notificações}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 46d5d3a0..3251eec 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Imposs. reconhecer rosto"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usar impressão digital"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ligado."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentagem da bateria desconhecida."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ligado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desativados ativo"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}other{Mais # notificações no grupo.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}many{Mais # notificações no grupo.}other{Mais # notificações no grupo.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"O ecrã está bloqueado na orientação horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"O ecrã está bloqueado na orientação vertical."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Vitrina de sobremesas"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Zona Wi-Fi"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"A ativar..."</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Poup. dados ativada"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}other{# dispositivos}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}many{# dispositivos}other{# dispositivos}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmara em utilização"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dados móveis"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Está no modo convidado"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo utilizador, o modo convidado é fechado e todas as apps e dados da sessão de convidado atual são eliminados."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Só é possível criar um utilizador.}other{É possível adicionar até # utilizadores.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Só é possível criar um utilizador.}many{É possível adicionar até # utilizadores.}other{É possível adicionar até # utilizadores.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Remover o utilizador?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sobreposição de legendas"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ativar"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Definições"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"A app está fixada"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Página inicial para soltar."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Lembrar-me"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Anular"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}other{# horas}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}other{# minutos}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}many{# horas}other{# horas}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}many{# minutos}other{# minutos}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Poupança de bateria"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Início"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Esquema"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo adicional"</string>
@@ -667,8 +672,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece.\nToque para obter mais informações."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"O telemóvel tenta arrefecer automaticamente. Pode continuar a utilizá-lo, mas este poderá funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, funcionará normalmente."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Veja os passos de manutenção"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desligar o carregador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema ao carregar este dispositivo. Desligue o transformador e tenha cuidado porque o cabo pode estar quente."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"Desligue o dispositivo"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"O dispositivo está a ficar quente perto da porta de carregamento. Se estiver ligado a um carregador ou um acessório USB, desligue-o e tenha cuidado, uma vez que o cabo também pode estar quente."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver os passos a ter em consideração"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atalho esquerdo"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atalho direito"</string>
@@ -778,7 +783,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ativar/desativar"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}other{# controlos adicionados.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}many{# controlos adicionados.}other{# controlos adicionados.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionados aos favoritos, posição <xliff:g id="NUMBER">%d</xliff:g>"</string>
@@ -935,7 +940,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar mosaico"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativa}other{# apps estão ativas}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativa}many{# apps estão ativas}other{# apps estão ativas}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Novas informações"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativas"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas apps estão ativas e a funcionar, mesmo quando não as está a usar. Isto melhora a sua funcionalidade, mas também afeta a autonomia da bateria."</string>
@@ -965,7 +970,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"A câmara está desativada"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"O microfone está desativado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmara e o microfone estão desativados"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}other{# notificações}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}many{# notificações}other{# notificações}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"A transmitir"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 59aee9b..2f9a36e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -202,7 +204,7 @@
     <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opção \"Sensores desativados\" está ativa"</string>
     <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string>
     <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}other{Mais # notificações no grupo.}}"</string>
+    <string name="notification_group_overflow_description" msgid="7176322877233433278">"{count,plural, =1{Mais # notificação no grupo.}one{Mais # notificação no grupo.}many{Mais # de notificações no grupo.}other{Mais # notificações no grupo.}}"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"A tela está bloqueada na orientação paisagem."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"A tela está bloqueada na orientação retrato."</string>
     <string name="dessert_case" msgid="9104973640704357717">"Mostruário de sobremesas"</string>
@@ -250,7 +252,7 @@
     <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Ponto de acesso"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Ativando…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Economia de dados ativada"</string>
-    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}other{# dispositivos}}"</string>
+    <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# dispositivo}one{# dispositivo}many{# de dispositivos}other{# dispositivos}}"</string>
     <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lanterna"</string>
     <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Câmera em uso"</string>
     <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Dados móveis"</string>
@@ -351,7 +353,7 @@
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Você está no modo visitante"</string>
     <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Ao adicionar um novo usuário, o dispositivo vai sair do modo visitante e excluir todos os apps e dados da Sessão de visitante atual."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}other{Você pode adicionar até # usuários.}}"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Você só pode criar 1 usuário.}one{Você pode adicionar até # usuário.}many{Você pode adicionar até # de usuários.}other{Você pode adicionar até # usuários.}}"</string>
     <string name="user_remove_user_title" msgid="9124124694835811874">"Remover usuário?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Todos os apps e dados deste usuário serão excluídos."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Sobreposição de legendas"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ativar"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desativar"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Som e vibração"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Configurações"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
@@ -537,8 +541,8 @@
     <string name="notification_menu_snooze_action" msgid="5415729610393475019">"Lembrete"</string>
     <string name="snooze_undo" msgid="2738844148845992103">"Desfazer"</string>
     <string name="snoozed_for_time" msgid="7586689374860469469">"Adiada para <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
-    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}other{# horas}}"</string>
-    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}other{# minuto}}"</string>
+    <string name="snoozeHourOptions" msgid="2332819756222425558">"{count,plural, =1{# hora}=2{# horas}one{# hora}many{# de horas}other{# horas}}"</string>
+    <string name="snoozeMinuteOptions" msgid="2222082405822030979">"{count,plural, =1{# minuto}one{# minuto}many{# de minutos}other{# minuto}}"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"Economia de bateria"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Botão <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo extra"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecte o carregador"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema com o carregamento deste dispositivo. Desconecte o adaptador de energia com cuidado, já que o cabo pode estar quente."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver etapas de cuidado"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Atalho à esquerda"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Atalho à direita"</string>
@@ -778,7 +785,7 @@
     <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
-    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}other{# controles adicionados.}}"</string>
+    <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
     <string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -935,7 +942,7 @@
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
     <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
-    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}other{# apps estão ativos}}"</string>
+    <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
     <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
@@ -965,7 +972,7 @@
     <string name="dream_overlay_status_bar_camera_off" msgid="5273073778969890823">"A câmera está desativada"</string>
     <string name="dream_overlay_status_bar_mic_off" msgid="8366534415013819396">"O microfone está desativado"</string>
     <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmera e o microfone estão desativados"</string>
-    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}other{# notificações}}"</string>
+    <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}one{# notificação}many{# notificações}other{# notificações}}"</string>
     <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string>
     <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitindo"</string>
     <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c4ee3ca..683774c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosiți amprenta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Chip nerecunoscut"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Folosește amprenta"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Conectat prin Bluetooth."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procentajul bateriei este necunoscut."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Suprapunere pe subtitrări"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activați"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"dezactivați"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sunete și vibrații"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Setări"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activat"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Dezactivați"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponibil"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Dezactivat"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Bară de navigare"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Aspect"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tip de buton din extrema stângă"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtingeți pentru mai multe informații"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonul va încerca automat să se răcească. Puteți folosi telefonul în continuare, dar este posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vedeți pașii pentru îngrijire"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Deconectați încărcătorul"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Există o problemă la încărcarea acestui dispozitiv. Deconectați adaptorul de curent și aveți grijă, deoarece cablul poate fi cald."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Vedeți pașii pentru îngrijire"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Comanda rapidă din stânga"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Comanda rapidă din dreapta"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 682dcb7..e848857 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицо не распознано."</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Используйте отпечаток."</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-соединение установлено."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Уровень заряда батареи в процентах неизвестен."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>: подключено."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Быстрая зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Медленная зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Наложение субтитров"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"включить"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"отключить"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрация"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Открыть настройки"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Приложение закреплено"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Главный экран\"."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Вкл."</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Откл."</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Недоступно"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Отключено"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Панель навигации"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Расположение кнопок"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Дополнительный тип кнопки \"Влево\""</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Пока телефон не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон остынет автоматически.\n\nОбратите внимание, что до тех пор он может работать медленнее, чем обычно."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Подробнее о действиях при перегреве…"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Отключите зарядное устройство"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Во время зарядки возникла проблема. Отключите адаптер питания. Будьте осторожны, кабель может быть горячим."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Подробнее о действиях при перегреве…"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ярлык слева"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Ярлык справа"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index ea89e2b..fcff90d 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"මුහුණ හඳුනා ගත නොහැක"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත කරන්න"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"බ්ලූටූත් සම්බන්ධිතයි."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"බැටරි ප්‍රතිශතය නොදනී."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> වෙත සම්බන්ධ කරන ලදි."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • වේගයෙන් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • සෙමින් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"සිරස්තල උඩැතිරිය"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"සබල කරන්න"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"අබල කරන්න"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ශබ්ද සහ කම්පනය"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"සැකසීම්"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"යෙදුම අමුණා ඇත"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ශ කර ආපසු අල්ලාගෙන සිටින්න."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට මුල් පිටුව ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ක්‍රියාත්මකයි"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ක්‍රියාවිරහිතයි"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ලබා ගත නොහැකිය"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"අබලයි"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"සංචලන තීරුව"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"පිරිසැලසුම"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"අමතර වම් බොත්තම් වර්ගය"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය.\nතව තතු සඳහා තට්ටු කරන්න"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"ඔබගේ දුරකථනය ස්වයංක්‍රියව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකිය, නමුත් එය සෙමින් ධාවනය විය හැකිය.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්‍ය ලෙස ධාවනය වනු ඇත."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"රැකවරණ පියවර බලන්න"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"චාජරය පේනුවෙන් ඉවත් කරන්න"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"මෙම උපාංගය ආරෝපණ කිරීමේ ගැටලුවක් තිබේ බල ඇඩැප්ටරය ගලවා කේබලය උණුසුම් විය හැකි බැවින් පරෙස්සම් වන්න."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"රැකවරණ පියවර බලන්න"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"වම් කෙටි මග"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"දකුණු කෙටි මග"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 7961224..eefb1de 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Tvár sa nedá rozpoznať"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Používať radšej odtlačok"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth pripojené."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percento batérie nie je známe."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Pripojené k zariadeniu <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Prekrytie titulkov"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"povoliť"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zakázať"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Zvuk a vibrácie"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavenia"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikácia je pripnutá"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidiel Späť a Domov."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Zapnuté"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Vypnuté"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nedostupné"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Deaktivované"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"ďalšie informácie"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigačný panel"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Rozloženie"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Dodatočný typ ľavého tlačidla"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu.\nViac sa dozviete po klepnutí."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude telefón fungovať ako normálne."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobraziť opatrenia"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odpojte nabíjačku"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Vyskytol sa problém s nabíjaním tohto zariadenia. Odpojte nabíjačku a postupujte opatrne, pretože kábel môže byť horúci."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobraziť opatrenia"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Ľavá skratka"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Pravá skratka"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 89fdf32..9140361 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Obraz ni bil prepoznan."</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Uporabite prstni odtis."</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Povezava Bluetooth vzpostavljena."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Neznan odstotek napolnjenosti baterije."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezava vzpostavljena z: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hitro polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Počasno polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Prekrivni podnapisi"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogoči"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogoči"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Zvok in vibriranje"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Nastavitve"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je pripeta"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Vklopljeno"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Izklopljeno"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ni na voljo"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Onemogočeno"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Vrstica za krmarjenje"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Postavitev"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Vrsta dodatnega levega gumba"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Nekatere funkcije bodo med ohlajanjem telefona omejene.\nDotaknite se za več informacij"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se telefon ohladi, bo zopet deloval kot običajno."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Oglejte si navodila za ukrepanje"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Odklopite polnilnik"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Pri polnjenju te naprave je prišlo do težave. Previdno odklopite napajalnik, ker se je kabel morda segrel."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Oglejte si navodila za ukrepanje"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Leva bližnjica"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Desna bližnjica"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index dfdebd2..99536cb 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Fytyra nuk mund të njihet"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Përdor më mirë gjurmën e gishtit"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Pajisja është lidhur me \"bluetooth\"."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Përqindja e baterisë e panjohur."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet shpejt • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet ngadalë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Mbivendosja e titrave"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivizo"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"çaktivizo"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Tingulli dhe dridhjet"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Cilësimet"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacioni është i gozhduar"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Kreu\" për ta hequr nga gozhdimi."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aktiv"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Joaktiv"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nuk ofrohet"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Joaktiv"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Shiriti i navigimit"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Struktura"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Lloji i butonit shtesë majtas"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Disa veçori janë të kufizuara kur telefoni është duke u ftohur.\nTrokit për më shumë informacione"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Shiko hapat për kujdesin"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Shkëput karikuesin"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ka një problem me karikimin e kësaj pajisjeje. Hiqe spinën dhe trego kujdes pasi kablloja mund të jetë e ngrohtë."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Shiko hapat për kujdesin"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Shkurtorja majtas"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Shkurtorja djathtas"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b1f9bb9..8b9822d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Лице није препознато"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користите отисак прста"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth је прикључен."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Проценат напуњености батерије није познат."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Повезани сте са <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Преклапање титлова"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"омогућите"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"онемогућите"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Звук и вибрирање"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Подешавања"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Апликација је закачена"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Преглед да бисте га откачили."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Почетна да бисте га откачили."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Укључено"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Искључено"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Недоступно"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Онемогућено"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Трака за навигацију"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Распоред"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Додатни тип левог дугмета"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Неке функције су ограничене док се телефон не охлади.\nДодирните за више информација"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон ће аутоматски покушати да се охлади. И даље ћете моћи да користите телефон, али ће спорије реаговати.\n\nКада се телефон охлади, нормално ће радити."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Погледајте упозорења"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Искључите пуњач из струје"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Дошло је до проблема са пуњењем овог уређаја. Искључите адаптер из напајања и будите пажљиви јер кабл може да буде топао."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Погледајте упозорења"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Лева пречица"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Десна пречица"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 9c75341..374d552 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet kändes inte igen"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Använd fingeravtryck"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ansluten."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Okänd batterinivå."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas snabbt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas långsamt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Överlagring av textning"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivera"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"inaktivera"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Ljud och vibration"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Inställningar"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Appen har fästs"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Översikt om du vill lossa skärmen."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Startsida om du vill lossa skärmen."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"På"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Av"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Inte tillgängligt"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Inaktiverat"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Navigeringsfält"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Knapptyp för extra vänster"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Vissa funktioner är begränsade medan telefonen svalnar.\nTryck för mer information"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Mobilen försöker svalna automatiskt. Du kan fortfarande använda mobilen, men den kan vara långsammare än vanligt.\n\nMobilen fungerar som vanligt när den har svalnat."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Visa alla skötselråd"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Koppla ur laddaren"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Det går inte att ladda denna enhet. Koppla ur nätadaptern, men var försiktig eftersom kabeln kan vara varm."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Visa alla skötselråd"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Vänster genväg"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Höger genväg"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index b978935..79e542f 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Imeshindwa kutambua uso"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Badala yake, tumia alama ya kidole"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth imeunganishwa."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Asilimia ya betri haijulikani."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji kwa kasi • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji polepole • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Kuwekelea manukuu"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"washa"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zima"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Sauti na mtetemo"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Mipangilio"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Programu imebandikwa"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha kurudisha Nyuma na cha Mwanzo kwa pamoja ili ubandue."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Imewashwa"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Imezimwa"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Hakipatikani"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Imezimwa"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Sehemu ya viungo muhimu"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Mpangilio"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Aina ya kitufe cha kushoto cha ziada"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa.\nGusa ili upate maelezo zaidi"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole. \n\nPindi simu yako itakapopoa, itaendelea kufanya kazi kama kawaida."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Angalia hatua za utunzaji"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Chomoa chaja"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kuna tatizo la kuchaji kifaa hiki. Chomoa adapta ya nishati na uwe mwangalifu, huenda kebo ni moto."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Angalia hatua za ulinzi"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Njia ya mkato ya kushoto"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Njia ya mkato ya kulia"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index d638c9d..f4d4824 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -49,54 +49,29 @@
 
     <dimen name="status_view_margin_horizontal">8dp</dimen>
 
-    <!-- Distance that the full shade transition takes in order to complete by tapping on a button
-         like "expand". -->
+    <!-- Lockscreen shade transition values -->
     <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order to complete.  -->
     <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for media to fully transition to
-         the shade -->
-    <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for scrim to fully transition to
-         the shade (in alpha) -->
+    <!-- Media transition distance = qs delay + qs distance   -->
+    <dimen name="lockscreen_shade_media_transition_distance">129.28dp</dimen>
     <dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
-
     <!-- The notifications scrim transition should start when the other scrims' transition is at
          95%. -->
     <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
-
     <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
-         transition. -->
+        transition. -->
     <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the keyguard content on
-         NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
     <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the notification shell to fully
-         expand. -->
     <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the Quick Settings to fully
-         fade and expand. -->
-    <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
-    <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
-         change.
-         On split-shade, there should be no depth effect, so setting the value to 0. -->
+    <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_notifications_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_notifications_scrim_transition_delay</dimen>
+    <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+    <!-- On split-shade, the QS squish transition should start from half height.  -->
+    <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item>
+    <!-- On split-shade, there should be no depth effect, so setting the value to 0.  -->
     <dimen name="lockscreen_shade_depth_controller_transition_distance">0dp</dimen>
-
-    <!-- Distance that the full shade transition takes in order for the UDFPS Keyguard View to fully
-         fade. -->
     <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
-    <!-- Used for StatusBar to know that a transition is in progress. At the moment it only checks
-         whether the progress is > 0, therefore this value is not very important. -->
     <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
-
     <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
 
     <!-- Roughly the same distance as media on LS to media on QS. We will translate by this value
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index c0071cb..80628f9 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,9 +35,6 @@
     <!-- How many lines to show in the security footer -->
     <integer name="qs_security_footer_maxLines">1</integer>
 
-    <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
-    <bool name="allow_force_nav_bar_handle_opaque">false</bool>
-
     <bool name="config_use_large_screen_shade_header">true</bool>
 
     <!-- Whether to show the side fps hint while on bouncer -->
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 008299b..a587e5a 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -73,4 +73,24 @@
     <dimen name="large_dialog_width">472dp</dimen>
 
     <dimen name="large_screen_shade_header_height">42dp</dimen>
+
+    <!-- Lockscreen shade transition values -->
+    <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
+    <dimen name="lockscreen_shade_full_transition_distance">80dp</dimen>
+    <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
+    <dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_notifications_scrim_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_notif_shelf_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_transition_delay">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+    <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+    <!-- On large screen portrait, the QS squish transition should start from half height.  -->
+    <item name="lockscreen_shade_qs_squish_start_fraction" type="dimen" format="float" >0.5</item>
+    <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_udfps_keyguard_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+    <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index a0bf072..3d8da8a 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -23,7 +23,7 @@
     <dimen name="status_view_margin_horizontal">124dp</dimen>
     <dimen name="keyguard_clock_top_margin">80dp</dimen>
     <dimen name="keyguard_status_view_bottom_margin">80dp</dimen>
-    <dimen name="bouncer_user_switcher_y_trans">90dp</dimen>
+    <dimen name="bouncer_user_switcher_y_trans">200dp</dimen>
 
     <dimen name="large_screen_shade_header_left_padding">24dp</dimen>
     <dimen name="qqs_layout_padding_bottom">40dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0015fbc..1c795bf 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"முகத்தை கண்டறிய இயலவில்லை"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"கைரேகையை உபயோகிக்கவும்"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"புளூடூத் இணைக்கப்பட்டது."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"பேட்டரி சதவீதம் தெரியவில்லை."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"மேலடுக்கப்பட்ட வசனங்கள்"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"இயக்கும்"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"ஒலி &amp; அதிர்வு"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"அமைப்புகள்"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்பு பட்டன்களைத் தொட்டுப் பிடிக்கவும்."</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ஆன்"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ஆஃப்"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"இல்லை"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"முடக்கப்பட்டது"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"வழிசெலுத்தல் பட்டி"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"தளவமைப்பு"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"கூடுதல் இடப்புற பட்டன் வகை"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"மொபைலின் வெப்ப அளவு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"உங்கள் மொபைலின் வெப்ப அளவு தானாகவே குறையும். தொடர்ந்து நீங்கள் மொபைலைப் பயன்படுத்தலாம், ஆனால் அதன் வேகம் குறைவாக இருக்கக்கூடும்.\n\nமொபைலின் வெப்ப அளவு குறைந்தவுடன், அது இயல்பு நிலையில் இயங்கும்."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"சார்ஜரைத் துண்டிக்கவும்"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"இந்தச் சாதனத்தைச் சார்ஜ் செய்வதில் சிக்கல் உள்ளது. பவர் அடாப்டரைத் துண்டிக்கவும், கேபிள் சூடாக இருக்கக்கூடும் என்பதால் கவனமாகக் கையாளவும்."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"இடப்புற ஷார்ட்கட்"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"வலப்புற ஷார்ட்கட்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 228d89d..b278f22 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ముఖం గుర్తించడం కుదరలేదు"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"బదులుగా వేలిముద్రను ఉపయోగించండి"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"బ్యాటరీ శాతం తెలియదు."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"క్యాప్షన్‌లు ఓవర్‌లే"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ప్రారంభించు"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"నిలిపివేయండి"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"సౌండ్ &amp; వైబ్రేషన్"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"సెట్టింగ్‌లు"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"యాప్ పిన్ చేయబడి ఉంది"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి &amp; అలాగే పట్టుకోండి."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు హోమ్‌ని తాకి &amp; అలాగే పట్టుకోండి."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ఆన్"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ఆఫ్ చేయి"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"అందుబాటులో లేదు"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"డిజేబుల్ చేయబడింది"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"మరింత తెలుసుకోండి"</string>
     <string name="nav_bar" msgid="4642708685386136807">"నావిగేషన్ బార్"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"లేఅవుట్"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"అత్యంత ఎడమ వైపు ఉన్న బటన్ రకం"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ ఆటోమేటిక్‌గా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ప్లగ్ నుండి ఛార్జర్‌ తీసివేయండి"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ఈ పరికరాన్ని ఛార్జ్ చేయడంలో సమస్య ఉంది. పవర్ అడాప్టర్‌ను ప్లగ్ నుండి తీసివేసి, కేబుల్ ఏమైనా వేడిగా అయితే తగిన జాగ్రత్తలు తీసుకోండి."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ఎడమవైపు షార్ట్‌కట్"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"కుడివైపు షార్ట్‌కట్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 42f8ae7..ec0e365 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"ไม่รู้จักใบหน้า"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ใช้ลายนิ้วมือแทน"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"เชื่อมต่อบลูทูธแล้ว"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ไม่ทราบเปอร์เซ็นต์แบตเตอรี่"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"เชื่อมต่อกับ <xliff:g id="BLUETOOTH">%s</xliff:g> แล้ว"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"การวางซ้อนคำบรรยายภาพ"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"เปิดใช้"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ปิดใช้"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"เสียงและการสั่น"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"การตั้งค่า"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ปักหมุดแอปอยู่"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกปักหมุด"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกปักหมุด แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกปักหมุด"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"เปิด"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ปิด"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ไม่พร้อมใช้งาน"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"ปิดใช้"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"แถบนำทาง"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"การจัดวาง"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ประเภทปุ่มทางซ้ายเพิ่มเติม"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์เย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่โทรศัพท์อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ดูขั้นตอนในการดูแลรักษา"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"ถอดปลั๊กที่ชาร์จ"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"พบปัญหาในการชาร์จอุปกรณ์นี้ ถอดปลั๊กอะแดปเตอร์ด้วยความระมัดระวังเพราะสายอาจร้อน"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ดูขั้นตอนในการดูแลรักษา"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"ทางลัดทางซ้าย"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"ทางลัดทางขวา"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 8f79ec5..c0b3588 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Hindi makilala ang mukha"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gumamit ng fingerprint"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Nakakonekta ang Bluetooth."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Hindi alam ang porsyento ng baterya."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Nakakonekta sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Overlay ng mga caption"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"i-enable"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"i-disable"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Tunog at pag-vibrate"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Mga Setting"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Naka-pin ang app"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Overview upang mag-unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Home upang mag-unpin."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"I-on"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"I-off"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Hindi available"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Naka-disable"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"matuto pa"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigation bar"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Uri ng extra na button ng kaliwa"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Limitado ang ilang feature habang nagku-cool down ang telepono.\nMag-tap para sa higit pang impormasyon"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Awtomatikong susubukan ng iyong telepono na mag-cool down. Magagamit mo pa rin ang iyong telepono, ngunit maaaring mas mabagal ang paggana nito.\n\nKapag nakapag-cool down na ang iyong telepono, gagana na ito nang normal."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Tingnan ang mga hakbang sa pangangalaga"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Hugutin ang charger"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"May isyu sa pag-charge ng device na ito. Hugutin ang power adapter at mag-ingat dahil maaaring mainit ang cable."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Tingnan ang mga hakbang sa pangangalaga"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Kaliwang shortcut"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Kanang shortcut"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 687be0f..389178a 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Yüz tanınamadı"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bunun yerine parmak izi kullanın"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth bağlandı."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pil yüzdesi bilinmiyor."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hızlı şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yavaş şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Altyazı yer paylaşımı"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"etkinleştir"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"devre dışı bırak"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Ses ve titreşim"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ayarlar"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Uygulama sabitlendi"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Ana sayfaya dokunup basılı tutun."</string>
@@ -576,7 +579,7 @@
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Klavye Kısayolları"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klavye düzenini değiştir"</string>
     <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Uygulamalar"</string>
-    <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Asist"</string>
+    <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"Asistan"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Tarayıcı"</string>
     <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Kişiler"</string>
     <string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"E-posta"</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Açık"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Kapalı"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Kullanılamıyor"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Devre dışı bırakıldı"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Gezinme çubuğu"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Düzen"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra sol düğme türü"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bakımla ilgili adımlara bakın"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Şarj cihazını çıkarın"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu cihaz şarj edilirken bir sorun oluştu. Güç adaptörünün fişini çekin. Kablo sıcak olabileceğinden fişi çekerken dikkatli olun."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Bakımla ilgili adımlara bakın"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Sol kısayol"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Sağ kısayol"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index bd5ec92..77966e8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Обличчя не розпізнано"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скористайтеся відбитком"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth під’єднано."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Швидке заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Повільне заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Накласти субтитри"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"увімкнути"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"вимкнути"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Звук і вібрація"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Налаштування"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Додаток закріплено"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\"."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Увімкнено"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Вимкнено"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Недоступно"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Вимкнено"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Панель навігації"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Макет"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Додатковий тип кнопки ліворуч"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Під час охолодження деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон охолоджуватиметься автоматично. Ви можете далі користуватися телефоном, але він може працювати повільніше.\n\nКоли телефон охолоне, він працюватиме належним чином."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Переглянути запобіжні заходи"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Відключіть зарядний пристрій"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Виникла проблема із заряджанням пристрою. Відключіть адаптер живлення, однак будьте обережні, оскільки кабель може бути гарячим."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Переглянути застереження"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Комбінація клавіш ліворуч"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Комбінація клавіш праворуч"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0123d30..4ebbc70 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"چہرے کی پہچان نہیں ہو سکی"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"اس کے بجائے فنگر پرنٹ استعمال کریں"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوٹوتھ مربوط ہے۔"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"بیٹری کی فیصد نامعلوم ہے۔"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"کیپشنز کا اوورلے"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"فعال کریں"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیر فعال کریں"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"آواز اور وائبریشن"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"ترتیبات"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"اس سے یہ اس وقت تک منظر میں رہتی ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ کے بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"اس سے یہ اس وقت تک منظر میں رہتی ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"آن"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"آف"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"غیر دستیاب ہے"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"غیر فعال ہے"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"نیویگیشن بار"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"لے آؤٹ"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"بائيں جانب کی اضافی بٹن کی قسم"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"فون کے ٹھنڈے ہو جانے تک کچھ خصوصیات محدود ہیں۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nایک بار آپ کا فون ٹھنڈا ہوجائے تو یہ معمول کے مطابق چلے گا۔"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"چارجر ان پلگ کریں"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"اس آلہ کو چارج کرنے میں ایک مسئلہ ہے۔ پاور ایڈاپٹر کو ان پلگ کریں اور دھیان دیں کیونکہ تار گرم ہو سکتا ہے۔"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"بائيں جانب کا شارٹ کٹ"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"دائیں جانب کا شارٹ کٹ"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0ec68f9..6432d75 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Yuz aniqlanmadi"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmoq izi orqali urining"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ulandi."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareya quvvati foizi nomaʼlum."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ulangan: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Taglavhalarni chiqarish"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"faollashtirish"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"faolsizlantirish"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Tovush va tebranish"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Sozlamalar"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Ilova mahkamlandi"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmalarni birga bosib turing."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Yoniq"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Yoqilmagan"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Mavjud emas"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Faolsizlantirilgan"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"batafsil"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigatsiya paneli"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Tugmalar joylashuvi"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Qo‘shimcha Chapga tugmasi turi"</string>
@@ -667,8 +671,8 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon sovib qolganda ayrim funksiyalari ishlamasligi mumkin.\nBatafsil axborot uchun bosing"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon avtomatik ravishda o‘zini sovitadi. Telefoningizdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Batafsil axborot"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Quvvatlash moslamasini uzing"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu qurilmani quvvatlashda muammo bor. Quvvat adapteri va kabelni tarmoqdan uzing, ular qizib ketgan boʻlishi mumkin."</string>
+    <string name="high_temp_alarm_title" msgid="8654754369605452169">"Qurilmani uzing"</string>
+    <string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Qurilmangiz quvvatlash porti yaqinida qizib ketmoqda. Agar quvvatlagich yoki USB aksessuarga ulangan boʻlsa, kabel qizib ketmasidan uni darhol uzing."</string>
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Batafsil axborot"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Chapga yorlig‘i"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"O‘ngga yorlig‘i"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 231a7d0..c0e7b2f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Không nhận ra khuôn mặt"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Hãy dùng vân tay"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Đã kết nối bluetooth."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Tỷ lệ phần trăm pin không xác định."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -339,8 +341,7 @@
     <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc nhanh • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc chậm • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <!-- no translation found for keyguard_indication_charging_time_dock (3149328898931741271) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
@@ -420,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Lớp phủ phụ đề"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"bật"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Âm thanh và chế độ rung"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Cài đặt"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
@@ -595,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Đang bật"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Đang tắt"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Không có sẵn"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Đã tắt"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"Thanh điều hướng"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Bố cục"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Loại nút bổ sung bên trái"</string>
@@ -668,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn có thể sử dụng điện thoại, nhưng điện thoại có thể chạy chậm hơn. \n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Xem các bước chăm sóc"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Rút phích cắm bộ sạc"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Đã xảy ra sự cố khi sạc thiết bị này. Hãy rút phích cắm bộ chuyển đổi điện và cẩn thận vì dây cáp có thể nóng."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Xem các bước chăm sóc"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Lối tắt bên trái"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Lối tắt bên phải"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 17ed05d..df0b0e0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"人脸识别失败"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"改用指纹"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"蓝牙已连接。"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"电池电量百分比未知。"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重叠显示"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"启用"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"提示音和振动"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"设置"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"应用已固定"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“概览”即可取消固定屏幕。"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“主屏幕”即可取消固定屏幕。"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"开启"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"关闭"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"不可用"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"已停用"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"导航栏"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"布局"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"其他向左按钮类型"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"手机降温时,部分功能的使用会受限制。\n点按即可了解详情"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"您的手机将自动尝试降温。您依然可以使用您的手机,但是手机运行速度可能会更慢。\n\n手机降温后,就会恢复正常的运行速度。"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看处理步骤"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"拔下充电器"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"为此设备充电时出现问题。这可能是由数据线太热所导致,请拔下电源适配器并采取相应的处理措施。"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看处理步骤"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"向左快捷方式"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"向右快捷方式"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 121e943..67f94b7 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識臉孔"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電量百分比不明。"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重疊"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"音效和震動"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"已固定應用程式"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"應用程式將會固定在螢幕上顯示,直至您取消固定為止。按住「返回」和「概覽」按鈕即可取消固定。"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"應用程式將會固定在螢幕上顯示,直至您取消固定為止。按住「返回」按鈕和主按鈕即可取消固定。"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"開啟"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"關閉"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"無法使用"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"已停用"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"導覽列"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"配置"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"其他向左按鈕類型"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。您仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會恢復正常。"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看保養步驟"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"拔下充電器"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"為此裝置充電時發生問題。請拔除電源適配器並注意安全,因為連接線可能會發熱。"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看保養步驟"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"向左捷徑"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"向右捷徑"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index d4de3bdc..23189d0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識臉孔"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池電量不明。"</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重疊顯示"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"音效與震動"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"設定"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主畫面按鈕即可取消固定。"</string>
@@ -594,7 +598,8 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"開啟"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"關閉"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"無法使用"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"已停用"</string>
+    <!-- no translation found for accessibility_tile_disabled_by_policy_action_description (6958422730461646926) -->
+    <skip />
     <string name="nav_bar" msgid="4642708685386136807">"導覽列"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"配置"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"其他向左按鈕類型"</string>
@@ -667,8 +672,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,某些功能會受限。\n輕觸即可瞭解詳情"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。你仍可繼續使用手機,但是手機的運作速度可能會較慢。\n\n手機降溫完畢後,就會恢復正常的運作速度。"</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看處理步驟"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"拔除充電器"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"為這個裝置充電時發生問題。這可能是因為傳輸線過熱所致,請拔除電源變壓器並採取處理措施。"</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看處理步驟"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"向左快速鍵"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"向右快速鍵"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 69af44d..08cd7fc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -161,6 +161,8 @@
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
     <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
     <skip />
+    <string name="keyguard_face_failed" msgid="9044619102286917151">"Ayikwazi ukubona ubuso"</string>
+    <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kunalokho sebenzisa isigxivizo somunwe"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ixhunyiwe"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Iphesenti lebhethri alaziwa."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -419,6 +421,8 @@
     <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"Imbondela yamagama-ncazo"</string>
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"nika amandla"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"khubaza"</string>
+    <string name="sound_settings" msgid="8874581353127418308">"Umsindo nokudlidliza"</string>
+    <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Amasethingi"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"I-app iphiniwe"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe okuthi Emuva Nokubuka konke ukuze ususe ukuphina."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Lokhu kuyigcina ibonakala uze uyisuse. Thinta uphinde ubambe okuthi Emuva nokuthi Ekhaya ukuze ususe ukuphina."</string>
@@ -594,7 +598,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Vuliwe"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Valiwe"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Akutholakali"</string>
-    <string name="tile_disabled" msgid="373212051546573069">"Kukhutshaziwe"</string>
+    <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"funda kabanzi"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Ibha yokuzula"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Isakhiwo"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Uhlobo lwenkinobho engakwesokunxele engeziwe"</string>
@@ -667,8 +671,10 @@
     <string name="high_temp_notif_message" msgid="1277346543068257549">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bona izinyathelo zokunakekelwa"</string>
-    <string name="high_temp_alarm_title" msgid="2359958549570161495">"Khipha ishaja"</string>
-    <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kukhona inkinga yokushaja le divayisi. Khipha i-adaptha yamandla, uphinde unakekele njengoba ikhebuli kungenzeka lifudumele."</string>
+    <!-- no translation found for high_temp_alarm_title (8654754369605452169) -->
+    <skip />
+    <!-- no translation found for high_temp_alarm_notify_message (3917622943609118956) -->
+    <skip />
     <string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Bona izinyathelo zokunakekelwa"</string>
     <string name="lockscreen_shortcut_left" msgid="1238765178956067599">"Isinqamuleli sangakwesokunxele"</string>
     <string name="lockscreen_shortcut_right" msgid="4138414674531853719">"Isinqamuleli sangakwesokudla"</string>
diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml
index 499e24e..c67ac8d 100644
--- a/packages/SystemUI/res/values/bools.xml
+++ b/packages/SystemUI/res/values/bools.xml
@@ -18,4 +18,6 @@
 <resources>
     <!-- Whether to show the user switcher in quick settings when only a single user is present. -->
     <bool name="qs_show_user_switcher_for_single_user">false</bool>
+    <!-- Whether to show a custom biometric prompt size-->
+    <bool name="use_custom_bp_size">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index dd5987b..11dbe4a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -186,7 +186,7 @@
     <color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
     <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
     <color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
-    <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+    <color name="media_dialog_seekbar_progress">@android:color/system_accent1_200</color>
     <color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
     <color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ec22c60..37549c9 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -587,9 +587,6 @@
          when the double-press power gesture is used. Ignored if empty. -->
     <string translatable="false" name="config_cameraGesturePackage"></string>
 
-    <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
-    <bool name="allow_force_nav_bar_handle_opaque">true</bool>
-
     <!-- Whether a transition of ACTIVITY_TYPE_DREAM to the home app should play a home sound
          effect -->
     <bool name="config_playHomeSoundAfterDream">false</bool>
@@ -614,11 +611,39 @@
          2 - Override the setting to never bypass keyguard -->
     <integer name="config_face_unlock_bypass_override">0</integer>
 
+    <!-- Messages that should NOT be shown to the user during face authentication on keyguard.
+         This includes both lockscreen and bouncer. This should be used to hide messages that may be
+         too chatty or messages that the user can't do much about. Entries are defined in
+         android.hardware.biometrics.face@1.0 types.hal.
+
+         Although not visibly shown to the user, these acquired messages (sent per face auth frame)
+         are still counted towards the total frames to determine whether a deferred message
+         (see config_face_help_msgs_defer_until_timeout) meets the threshold % of frames to show on
+         face timeout. -->
+     <integer-array name="config_face_acquire_device_entry_ignorelist" translatable="false" >
+    </integer-array>
+
+    <!-- Which face help messages to defer until face auth times out. If face auth is cancelled
+         or ends on another error, then the message is never surfaced. May also never surface
+         if it doesn't meet a threshold % of authentication frames specified by.
+         config_face_help_msgs_defer_until_timeout_threshold. -->
+    <integer-array name="config_face_help_msgs_defer_until_timeout">
+    </integer-array>
+
+    <!-- Percentage of face auth frames received required to show a deferred message at
+         FACE_ERROR_TIMEOUT. See config_face_help_msgs_defer_until_timeout for messages
+         that are deferred.-->
+    <item name="config_face_help_msgs_defer_until_timeout_threshold"
+          translatable="false" format="float" type="dimen">
+        .75
+    </item>
+
     <!-- Which face help messages to surface when fingerprint is also enrolled.
          Message ids correspond with the acquired ids in BiometricFaceConstants -->
     <integer-array name="config_face_help_msgs_when_fingerprint_enrolled">
-        <item>25</item>
-        <item>26</item>
+        <item>3</item> <!-- TOO_DARK -->
+        <item>25</item> <!-- DARK_GLASSES -->
+        <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
     </integer-array>
 
     <!-- Whether the communal service should be enabled -->
@@ -629,11 +654,15 @@
 
     <!-- This value is used when calculating whether the device is in ambient light mode. It is
         light mode when the light sensor sample value exceeds above this value. -->
-    <integer name="config_ambientLightModeThreshold">10</integer>
+    <item name="config_ambientLightModeThreshold" translatable="false" format="float" type="dimen">
+        0.8
+    </item>
 
     <!-- This value is used when calculating whether the device is in ambient dark mode. It is
         dark mode when the light sensor sample value drops below this value. -->
-    <integer name="config_ambientDarkModeThreshold">5</integer>
+    <item name="config_ambientDarkModeThreshold" translatable="false" format="float" type="dimen">
+        0.4
+    </item>
 
     <!-- This value is used when calculating whether the device is in ambient light mode. Each
         sample contains light sensor events from this span of time duration. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2865606..2e57852 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -520,7 +520,7 @@
     <dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
     <dimen name="qs_tile_margin_top_bottom">4dp</dimen>
     <dimen name="qs_brightness_margin_top">8dp</dimen>
-    <dimen name="qs_brightness_margin_bottom">24dp</dimen>
+    <dimen name="qs_brightness_margin_bottom">16dp</dimen>
     <dimen name="qqs_layout_margin_top">16dp</dimen>
     <dimen name="qqs_layout_padding_bottom">24dp</dimen>
 
@@ -945,6 +945,8 @@
     <dimen name="biometric_dialog_medium_to_large_translation_offset">100dp</dimen>
     <!-- Y translation for credential contents when animating in -->
     <dimen name="biometric_dialog_credential_translation_offset">60dp</dimen>
+    <dimen name="biometric_dialog_width">240dp</dimen>
+    <dimen name="biometric_dialog_height">240dp</dimen>
 
     <!-- Biometric Auth Credential values -->
     <dimen name="biometric_auth_icon_size">48dp</dimen>
@@ -1223,6 +1225,17 @@
          fade and expand. -->
     <dimen name="lockscreen_shade_qs_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
 
+    <!-- Distance delay for the QS transition to start during the lockscreen shade expansion. -->
+    <dimen name="lockscreen_shade_qs_transition_delay">0dp</dimen>
+
+    <!-- Distance that it takes to complete the QS "squish" transition during the lockscreen shade
+         expansion. -->
+    <dimen name="lockscreen_shade_qs_squish_transition_distance">@dimen/lockscreen_shade_qs_transition_distance</dimen>
+
+    <!-- The fraction at which the QS "squish" transition should start during the lockscreen shade
+         expansion. 0 is fully collapsed, 1 is fully expanded. -->
+    <item type="dimen" format="float" name="lockscreen_shade_qs_squish_start_fraction">0</item>
+
     <!-- Distance that the full shade transition takes in order for depth of the wallpaper to fully
          change.  -->
     <dimen name="lockscreen_shade_depth_controller_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
@@ -1464,7 +1477,7 @@
     <dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
     <dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
     <dimen name="dream_overlay_grey_chip_width">56dp</dimen>
-    <dimen name="dream_overlay_status_bar_extra_margin">16dp</dimen>
+    <dimen name="dream_overlay_status_bar_extra_margin">8dp</dimen>
 
     <!-- Dream overlay complications related dimensions -->
     <dimen name="dream_overlay_complication_clock_time_text_size">86sp</dimen>
@@ -1477,14 +1490,14 @@
          if their end is aligned with the parent end. Represented as the percentage over from the
          start of the parent container. -->
     <item name="dream_overlay_complication_guide_end_percent" format="float" type="dimen">
-        0.75
+        0.5
     </item>
 
     <!-- The position of the start guide, which dream overlay complications can align their end to
          if their start is aligned with the parent start. Represented as the percentage over from
          the start of the parent container. -->
     <item name="dream_overlay_complication_guide_start_percent" format="float" type="dimen">
-        0.25
+        0.5
     </item>
 
     <!-- The position of the bottom guide, which dream overlay complications can align their top to
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c5b7ded..9324e8f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1862,10 +1862,10 @@
     <!-- URL for care instructions for overheating devices -->
     <string name="high_temp_dialog_help_url" translatable="false"></string>
 
-    <!-- Title for alarm dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=30] -->
-    <string name="high_temp_alarm_title">Unplug charger</string>
-    <!-- Text body for dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=300] -->
-    <string name="high_temp_alarm_notify_message">There\u2019s an issue charging this device. Unplug the power adapter, and take care as the cable may be warm.</string>
+    <!-- Title for alarm dialog alerting user the usb charger or accessorry has reached a certain temperature that should unplug the device immediately. [CHAR LIMIT=30] -->
+    <string name="high_temp_alarm_title">Unplug your device</string>
+    <!-- Text body for dialog alerting user the usb charger or accessorry has reached a certain temperature that should unplug the device immediately. [CHAR LIMIT=300] -->
+    <string name="high_temp_alarm_notify_message">Your device is getting warm near the charging port. If it\u2019s connected to a charger or USB accessory, unplug it, and take care as the cable may also be warm.</string>
     <!-- Text for See care steps button [CHAR LIMIT=300] -->
     <string name="high_temp_alarm_help_care_steps">See care steps</string>
     <!-- Text link directs to usb overheat help page. -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d087b1d..a734fa7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -580,6 +580,7 @@
     </style>
 
     <style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
+        <item name="android:thumb">@drawable/media_seekbar_thumb</item>
         <item name="android:thumbTint">?android:attr/textColorPrimary</item>
         <item name="android:progressDrawable">@drawable/media_squiggly_progress</item>
         <item name="android:progressTint">?android:attr/textColorPrimary</item>
@@ -978,6 +979,8 @@
         <!-- Padding for indeterminate progress bar -->
         <item name="progressBarStartPadding">12dp</item>
         <item name="progressBarEndPadding">16dp</item>
+
+        <item name="iconSize">25dp</item>
     </style>
 
     <style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large">
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
index cbab0a7..fafc774 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
@@ -23,9 +23,11 @@
 /** A [GoldenImagePathManager] that should be used for all SystemUI screenshot tests. */
 class SystemUIGoldenImagePathManager(
     pathConfig: PathConfig,
+    override val assetsPathRelativeToRepo: String = "tests/screenshot/assets"
 ) :
     GoldenImagePathManager(
         appContext = InstrumentationRegistry.getInstrumentation().context,
+        assetsPathRelativeToRepo = assetsPathRelativeToRepo,
         deviceLocalPath =
             InstrumentationRegistry.getInstrumentation()
                 .targetContext
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index f59a320..9040ea1 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -52,7 +52,7 @@
         "SystemUIUnfoldLib",
         "androidx.dynamicanimation_dynamicanimation",
         "androidx.concurrent_concurrent-futures",
-        "gson-prebuilt-jar",
+        "gson",
         "dagger2",
         "jsr330",
     ],
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index a030bf6..e77c650 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -42,13 +42,6 @@
     void onOverviewShown(boolean fromHome) = 6;
 
     /**
-     * Control the {@param alpha} of the option nav bar button (back-button in 2 button mode
-     * and home handle & background in gestural mode).  The {@param animate} is currently only
-     * supported for 2 button mode.
-     */
-    void setNavBarButtonAlpha(float alpha, boolean animate) = 19;
-
-    /**
      * Proxies motion events from the homescreen UI to the status bar. Only called when
      * swipe down is detected on WORKSPACE. The sender guarantees the following order of events on
      * the tracking pointer.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 0773347..0b0df83 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -17,11 +17,10 @@
 package com.android.systemui.shared.recents.model;
 
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.graphics.Bitmap.Config.ARGB_8888;
 
-import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED;
-
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Point;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
deleted file mode 100644
index 0f937bd..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.app.Activity;
-import android.view.View;
-import android.view.ViewHierarchyEncoder;
-
-import java.io.ByteArrayOutputStream;
-
-public class ActivityCompat {
-    private final Activity mWrapped;
-
-    public ActivityCompat(Activity activity) {
-        mWrapped = activity;
-    }
-
-    /**
-     * @see Activity#registerRemoteAnimations
-     */
-    public void registerRemoteAnimations(RemoteAnimationDefinitionCompat definition) {
-        mWrapped.registerRemoteAnimations(definition.getWrapped());
-    }
-
-    /**
-     * @see Activity#unregisterRemoteAnimations
-     */
-    public void unregisterRemoteAnimations() {
-        mWrapped.unregisterRemoteAnimations();
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
deleted file mode 100644
index be99b27..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.os.Handler;
-
-/**
- * Wrapper around internal ActivityOptions creation.
- */
-public abstract class ActivityOptionsCompat {
-
-    /**
-     * @return ActivityOptions for starting a task in freeform.
-     */
-    public static ActivityOptions makeFreeformOptions() {
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
-        return options;
-    }
-
-    public static ActivityOptions makeRemoteAnimation(
-            RemoteAnimationAdapterCompat remoteAnimationAdapter) {
-        return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped(),
-                remoteAnimationAdapter.getRemoteTransition().getTransition());
-    }
-
-    /**
-     * Constructs an ActivityOptions object that will delegate its transition handling to a
-     * `remoteTransition`.
-     */
-    public static ActivityOptions makeRemoteTransition(RemoteTransitionCompat remoteTransition) {
-        return ActivityOptions.makeRemoteTransition(remoteTransition.getTransition());
-    }
-
-    /**
-     * Returns ActivityOptions for overriding task transition animation.
-     */
-    public static ActivityOptions makeCustomAnimation(Context context, int enterResId,
-            int exitResId, final Runnable callback, final Handler callbackHandler) {
-        return ActivityOptions.makeCustomTaskAnimation(context, enterResId, exitResId,
-                callbackHandler,
-                new ActivityOptions.OnAnimationStartedListener() {
-                    @Override
-                    public void onAnimationStarted(long elapsedRealTime) {
-                        if (callback != null) {
-                            callbackHandler.post(callback);
-                        }
-                    }
-                }, null /* finishedListener */);
-    }
-
-    /**
-     * Sets the flag to freeze the recents task list reordering as a part of launching the activity.
-     */
-    public static ActivityOptions setFreezeRecentTasksList(ActivityOptions opts) {
-        opts.setFreezeRecentTasksReordering();
-        return opts;
-    }
-
-    /**
-     * Sets the launch event time from launcher.
-     */
-    public static ActivityOptions setLauncherSourceInfo(ActivityOptions opts, long uptimeMillis) {
-        opts.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER, uptimeMillis);
-        return opts;
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/KeyguardManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/KeyguardManagerCompat.java
deleted file mode 100644
index c42e7e3..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/KeyguardManagerCompat.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.app.KeyguardManager;
-import android.content.Context;
-
-public class KeyguardManagerCompat {
-    private final KeyguardManager mKeyguardManager;
-
-    public KeyguardManagerCompat(Context context) {
-        mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
-    }
-
-    public boolean isDeviceLocked(int userId) {
-        return mKeyguardManager.isDeviceLocked(userId);
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
deleted file mode 100644
index e6ae19e..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.shared.system;
-
-import android.content.Context;
-
-import com.android.internal.util.LatencyTracker;
-
-/**
- * @see LatencyTracker
- */
-public class LatencyTrackerCompat {
-
-    /** @see LatencyTracker */
-    public static void logToggleRecents(Context context, int duration) {
-        LatencyTracker.getInstance(context).logAction(LatencyTracker.ACTION_TOGGLE_RECENTS,
-                duration);
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 33e8e35..09cf7c5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -58,7 +58,7 @@
         mRemoteTransition = buildRemoteTransition(runner, appThread);
     }
 
-    RemoteAnimationAdapter getWrapped() {
+    public RemoteAnimationAdapter getWrapped() {
         return mWrapped;
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java
index 098698a..ab55037 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java
@@ -34,7 +34,7 @@
         mWrapped.addRemoteAnimation(transition, activityTypeFilter, adapter.getWrapped());
     }
 
-    RemoteAnimationDefinition getWrapped() {
+    public RemoteAnimationDefinition getWrapped() {
         return mWrapped;
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java
deleted file mode 100644
index cfb23f9..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.system;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
-
-import java.util.HashMap;
-
-public class ViewTreeObserverWrapper {
-
-    private static final HashMap<OnComputeInsetsListener, ViewTreeObserver>
-            sListenerObserverMap = new HashMap<>();
-    private static final HashMap<OnComputeInsetsListener, OnComputeInternalInsetsListener>
-            sListenerInternalListenerMap = new HashMap<>();
-
-    /**
-     * Register a callback to be invoked when the invoked when it is time to compute the window's
-     * insets.
-     *
-     * @param observer The observer to be added
-     * @param listener The callback to add
-     * @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
-     */
-    public static void addOnComputeInsetsListener(
-            @NonNull ViewTreeObserver observer, @NonNull OnComputeInsetsListener listener) {
-        final OnComputeInternalInsetsListener internalListener = internalInOutInfo -> {
-            final InsetsInfo inOutInfo = new InsetsInfo();
-            inOutInfo.contentInsets.set(internalInOutInfo.contentInsets);
-            inOutInfo.visibleInsets.set(internalInOutInfo.visibleInsets);
-            inOutInfo.touchableRegion.set(internalInOutInfo.touchableRegion);
-            listener.onComputeInsets(inOutInfo);
-            internalInOutInfo.contentInsets.set(inOutInfo.contentInsets);
-            internalInOutInfo.visibleInsets.set(inOutInfo.visibleInsets);
-            internalInOutInfo.touchableRegion.set(inOutInfo.touchableRegion);
-            internalInOutInfo.setTouchableInsets(inOutInfo.mTouchableInsets);
-        };
-        sListenerObserverMap.put(listener, observer);
-        sListenerInternalListenerMap.put(listener, internalListener);
-        observer.addOnComputeInternalInsetsListener(internalListener);
-    }
-
-    /**
-     * Remove a previously installed insets computation callback.
-     *
-     * @param victim The callback to remove
-     * @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
-     * @see #addOnComputeInsetsListener(ViewTreeObserver, OnComputeInsetsListener)
-     */
-    public static void removeOnComputeInsetsListener(@NonNull OnComputeInsetsListener victim) {
-        final ViewTreeObserver observer = sListenerObserverMap.get(victim);
-        final OnComputeInternalInsetsListener listener = sListenerInternalListenerMap.get(victim);
-        if (observer != null && listener != null) {
-            observer.removeOnComputeInternalInsetsListener(listener);
-        }
-        sListenerObserverMap.remove(victim);
-        sListenerInternalListenerMap.remove(victim);
-    }
-
-    /**
-     * Interface definition for a callback to be invoked when layout has
-     * completed and the client can compute its interior insets.
-     */
-    public interface OnComputeInsetsListener {
-        /**
-         * Callback method to be invoked when layout has completed and the
-         * client can compute its interior insets.
-         *
-         * @param inoutInfo Should be filled in by the implementation with
-         * the information about the insets of the window.  This is called
-         * with whatever values the previous OnComputeInsetsListener
-         * returned, if there are multiple such listeners in the window.
-         */
-        void onComputeInsets(InsetsInfo inoutInfo);
-    }
-
-    /**
-     * Parameters used with OnComputeInsetsListener.
-     */
-    public final static class InsetsInfo {
-
-        /**
-         * Offsets from the frame of the window at which the content of
-         * windows behind it should be placed.
-         */
-        public final Rect contentInsets = new Rect();
-
-        /**
-         * Offsets from the frame of the window at which windows behind it
-         * are visible.
-         */
-        public final Rect visibleInsets = new Rect();
-
-        /**
-         * Touchable region defined relative to the origin of the frame of the window.
-         * Only used when {@link #setTouchableInsets(int)} is called with
-         * the option {@link #TOUCHABLE_INSETS_REGION}.
-         */
-        public final Region touchableRegion = new Region();
-
-        /**
-         * Option for {@link #setTouchableInsets(int)}: the entire window frame
-         * can be touched.
-         */
-        public static final int TOUCHABLE_INSETS_FRAME =
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
-
-        /**
-         * Option for {@link #setTouchableInsets(int)}: the area inside of
-         * the content insets can be touched.
-         */
-        public static final int TOUCHABLE_INSETS_CONTENT =
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
-
-        /**
-         * Option for {@link #setTouchableInsets(int)}: the area inside of
-         * the visible insets can be touched.
-         */
-        public static final int TOUCHABLE_INSETS_VISIBLE =
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-
-        /**
-         * Option for {@link #setTouchableInsets(int)}: the area inside of
-         * the provided touchable region in {@link #touchableRegion} can be touched.
-         */
-        public static final int TOUCHABLE_INSETS_REGION =
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-
-        /**
-         * Set which parts of the window can be touched: either
-         * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
-         * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
-         */
-        public void setTouchableInsets(int val) {
-            mTouchableInsets = val;
-        }
-
-        int mTouchableInsets;
-
-        @Override
-        public int hashCode() {
-            int result = contentInsets.hashCode();
-            result = 31 * result + visibleInsets.hashCode();
-            result = 31 * result + touchableRegion.hashCode();
-            result = 31 * result + mTouchableInsets;
-            return result;
-        }
-
-        @Override
-        public boolean equals(@Nullable Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-
-            final InsetsInfo other = (InsetsInfo) o;
-            return mTouchableInsets == other.mTouchableInsets &&
-                    contentInsets.equals(other.contentInsets) &&
-                    visibleInsets.equals(other.visibleInsets) &&
-                    touchableRegion.equals(other.touchableRegion);
-        }
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
deleted file mode 100644
index 5577513..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.system;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
-
-import android.app.WindowConfiguration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.InsetsController;
-import android.view.InsetsFrameProvider;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
-import com.android.systemui.shared.recents.view.RecentsTransition;
-
-public class WindowManagerWrapper {
-
-    private static final String TAG = "WindowManagerWrapper";
-
-    public static final int TRANSIT_UNSET = WindowManager.TRANSIT_OLD_UNSET;
-    public static final int TRANSIT_NONE = WindowManager.TRANSIT_OLD_NONE;
-    public static final int TRANSIT_ACTIVITY_OPEN = WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
-    public static final int TRANSIT_ACTIVITY_CLOSE = WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-    public static final int TRANSIT_TASK_OPEN = WindowManager.TRANSIT_OLD_TASK_OPEN;
-    public static final int TRANSIT_TASK_CLOSE = WindowManager.TRANSIT_OLD_TASK_CLOSE;
-    public static final int TRANSIT_TASK_TO_FRONT = WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
-    public static final int TRANSIT_TASK_TO_BACK = WindowManager.TRANSIT_OLD_TASK_TO_BACK;
-    public static final int TRANSIT_WALLPAPER_CLOSE = WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
-    public static final int TRANSIT_WALLPAPER_OPEN = WindowManager.TRANSIT_OLD_WALLPAPER_OPEN;
-    public static final int TRANSIT_WALLPAPER_INTRA_OPEN =
-            WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
-    public static final int TRANSIT_WALLPAPER_INTRA_CLOSE =
-            WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
-    public static final int TRANSIT_TASK_OPEN_BEHIND = WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
-    public static final int TRANSIT_ACTIVITY_RELAUNCH = WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH;
-    public static final int TRANSIT_KEYGUARD_GOING_AWAY =
-            WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-    public static final int TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER =
-            WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-    public static final int TRANSIT_KEYGUARD_OCCLUDE = WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
-    public static final int TRANSIT_KEYGUARD_UNOCCLUDE =
-            WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
-
-    public static final int NAV_BAR_POS_INVALID = NAV_BAR_INVALID;
-    public static final int NAV_BAR_POS_LEFT = NAV_BAR_LEFT;
-    public static final int NAV_BAR_POS_RIGHT = NAV_BAR_RIGHT;
-    public static final int NAV_BAR_POS_BOTTOM = NAV_BAR_BOTTOM;
-
-    public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-
-    public static final int WINDOWING_MODE_UNDEFINED = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-    public static final int WINDOWING_MODE_FULLSCREEN =
-            WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-    public static final int WINDOWING_MODE_MULTI_WINDOW =
-            WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-
-    public static final int WINDOWING_MODE_FREEFORM = WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
-    public static final int ITYPE_EXTRA_NAVIGATION_BAR = InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-    public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = InsetsState.ITYPE_LEFT_TAPPABLE_ELEMENT;
-    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
-    public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = InsetsState.ITYPE_RIGHT_TAPPABLE_ELEMENT;
-    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT =
-            InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
-    public static final int ITYPE_SIZE = InsetsState.SIZE;
-
-    public static final int ANIMATION_DURATION_RESIZE = InsetsController.ANIMATION_DURATION_RESIZE;
-    public static final Interpolator RESIZE_INTERPOLATOR = InsetsController.RESIZE_INTERPOLATOR;
-
-    private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
-
-    public static WindowManagerWrapper getInstance() {
-        return sInstance;
-    }
-
-
-    /**
-     * Sets {@param providesInsetsTypes} as the inset types provided by {@param params}.
-     * @param params The window layout params.
-     * @param providesInsetsTypes The inset types we would like this layout params to provide.
-     */
-    public void setProvidesInsetsTypes(WindowManager.LayoutParams params,
-            int[] providesInsetsTypes) {
-        final int length = providesInsetsTypes.length;
-        params.providedInsets = new InsetsFrameProvider[length];
-        for (int i = 0; i < length; i++) {
-            params.providedInsets[i] = new InsetsFrameProvider(providesInsetsTypes[i]);
-        }
-    }
-
-    /**
-     * Overrides a pending app transition.
-     */
-    public void overridePendingAppTransitionMultiThumbFuture(
-            AppTransitionAnimationSpecsFuture animationSpecFuture, Runnable animStartedCallback,
-            Handler animStartedCallbackHandler, boolean scaleUp, int displayId) {
-        try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .overridePendingAppTransitionMultiThumbFuture(animationSpecFuture.getFuture(),
-                            RecentsTransition.wrapStartedListener(animStartedCallbackHandler,
-                                    animStartedCallback), scaleUp, displayId);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to override pending app transition (multi-thumbnail future): ", e);
-        }
-    }
-
-    /**
-     * Enable or disable haptic feedback on the navigation bar buttons.
-     */
-    public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
-        try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .setNavBarVirtualKeyHapticFeedbackEnabled(enabled);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to enable or disable navigation bar button haptics: ", e);
-        }
-    }
-
-    /**
-     * @param displayId the id of display to check if there is a software navigation bar.
-     *
-     * @return whether there is a soft nav bar on specific display.
-     */
-    public boolean hasSoftNavigationBar(int displayId) {
-        try {
-            return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(displayId);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Mirrors a specified display. The SurfaceControl returned is the root of the mirrored
-     * hierarchy.
-     *
-     * @param displayId The id of the display to mirror
-     * @return The SurfaceControl for the root of the mirrored hierarchy.
-     */
-    public SurfaceControl mirrorDisplay(final int displayId) {
-        try {
-            SurfaceControl outSurfaceControl = new SurfaceControl();
-            WindowManagerGlobal.getWindowManagerService().mirrorDisplay(displayId,
-                    outSurfaceControl);
-            return outSurfaceControl;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to reach window manager", e);
-        }
-        return null;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt
new file mode 100644
index 0000000..82ce1ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.util.AttributeSet
+
+/**
+ * Displays security messages for auth outside of the security method (pin, password, pattern), like
+ * biometric auth.
+ */
+class AuthKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
+    KeyguardMessageArea(context, attrs) {
+    override fun updateTextColor() {
+        setTextColor(ColorStateList.valueOf(Color.WHITE))
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
new file mode 100644
index 0000000..0075ddd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.keyguard
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.content.res.TypedArray
+import android.graphics.Color
+import android.util.AttributeSet
+import com.android.settingslib.Utils
+
+/** Displays security messages for the keyguard bouncer. */
+class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
+    KeyguardMessageArea(context, attrs) {
+    private val DEFAULT_COLOR = -1
+    private var mDefaultColorState: ColorStateList? = null
+    private var mNextMessageColorState: ColorStateList? = ColorStateList.valueOf(DEFAULT_COLOR)
+
+    override fun updateTextColor() {
+        var colorState = mDefaultColorState
+        mNextMessageColorState?.defaultColor?.let { color ->
+            if (color != DEFAULT_COLOR) {
+                colorState = mNextMessageColorState
+                mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR)
+            }
+        }
+        setTextColor(colorState)
+    }
+
+    override fun setNextMessageColor(colorState: ColorStateList?) {
+        mNextMessageColorState = colorState
+    }
+
+    override fun onThemeChanged() {
+        val array: TypedArray =
+            mContext.obtainStyledAttributes(intArrayOf(android.R.attr.textColorPrimary))
+        val newTextColors: ColorStateList = ColorStateList.valueOf(array.getColor(0, Color.RED))
+        array.recycle()
+        mDefaultColorState = newTextColors
+        super.onThemeChanged()
+    }
+
+    override fun reloadColor() {
+        mDefaultColorState = Utils.getColorAttr(context, android.R.attr.textColorPrimary)
+        super.reloadColor()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index b8fcb10..92ba619 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -50,7 +50,6 @@
     private final FalsingCollector mFalsingCollector;
     private final EmergencyButtonController mEmergencyButtonController;
     private CountDownTimer mCountdownTimer;
-    protected KeyguardMessageAreaController mMessageAreaController;
     private boolean mDismissing;
     protected AsyncTask<?, ?, ?> mPendingLockCheck;
     protected boolean mResumed;
@@ -80,14 +79,13 @@
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             LatencyTracker latencyTracker, FalsingCollector falsingCollector,
             EmergencyButtonController emergencyButtonController) {
-        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
+        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
+                messageAreaControllerFactory);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
         mFalsingCollector = falsingCollector;
         mEmergencyButtonController = emergencyButtonController;
-        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
-        mMessageAreaController = messageAreaControllerFactory.create(kma);
     }
 
     abstract void resetState();
@@ -95,7 +93,6 @@
     @Override
     public void onInit() {
         super.onInit();
-        mMessageAreaController.init();
     }
 
     @Override
@@ -134,6 +131,10 @@
 
     @Override
     public void showMessage(CharSequence message, ColorStateList colorState) {
+        if (mMessageAreaController == null) {
+            return;
+        }
+
         if (colorState != null) {
             mMessageAreaController.setNextMessageColor(colorState);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 87300c3..f26b905 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -17,9 +17,11 @@
 package com.android.keyguard;
 
 import android.annotation.CallSuper;
+import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.util.LatencyTracker;
@@ -44,7 +46,7 @@
     private final EmergencyButton mEmergencyButton;
     private final EmergencyButtonController mEmergencyButtonController;
     private boolean mPaused;
-
+    protected KeyguardMessageAreaController<BouncerKeyguardMessageArea> mMessageAreaController;
 
     // The following is used to ignore callbacks from SecurityViews that are no longer current
     // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
@@ -72,12 +74,24 @@
 
     protected KeyguardInputViewController(T view, SecurityMode securityMode,
             KeyguardSecurityCallback keyguardSecurityCallback,
-            EmergencyButtonController emergencyButtonController) {
+            EmergencyButtonController emergencyButtonController,
+            @Nullable KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
         super(view);
         mSecurityMode = securityMode;
         mKeyguardSecurityCallback = keyguardSecurityCallback;
         mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button);
         mEmergencyButtonController = emergencyButtonController;
+        if (messageAreaControllerFactory != null) {
+            try {
+                BouncerKeyguardMessageArea kma = view.requireViewById(R.id.bouncer_message_area);
+                mMessageAreaController = messageAreaControllerFactory.create(kma);
+                mMessageAreaController.init();
+                mMessageAreaController.setIsVisible(true);
+            } catch (IllegalArgumentException exception) {
+                Log.e("KeyguardInputViewController",
+                        "Ensure that a BouncerKeyguardMessageArea is included in the layout");
+            }
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
index 919b71b..f82e7db 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -55,6 +55,8 @@
     val bouncerIsOrWillShow: Boolean,
     val faceAuthenticated: Boolean,
     val faceDisabled: Boolean,
+    val faceLockedOut: Boolean,
+    val fpLockedOut: Boolean,
     val goingToSleep: Boolean,
     val keyguardAwakeExcludingBouncerShowing: Boolean,
     val keyguardGoingAway: Boolean,
@@ -65,7 +67,7 @@
     val scanningAllowedByStrongAuth: Boolean,
     val secureCameraLaunched: Boolean,
     val switchingUser: Boolean,
-    val udfpsBouncerShowing: Boolean
+    val udfpsBouncerShowing: Boolean,
 ) : KeyguardListenModel()
 /**
  * Verbose debug information associated with [KeyguardUpdateMonitor.shouldTriggerActiveUnlock].
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 5ab2fd0..c79fc2c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -17,9 +17,7 @@
 package com.android.keyguard;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
@@ -33,7 +31,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.policy.SystemBarUtils;
-import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
 import java.lang.ref.WeakReference;
@@ -41,7 +38,7 @@
 /***
  * Manages a number of views inside of the given layout. See below for a list of widgets.
  */
-public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
+public abstract class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
     /** Handler token posted with accessibility announcement runnables. */
     private static final Object ANNOUNCE_TOKEN = new Object();
 
@@ -50,15 +47,11 @@
      * lift-to-type from interrupting itself.
      */
     private static final long ANNOUNCEMENT_DELAY = 250;
-    private static final int DEFAULT_COLOR = -1;
 
     private final Handler mHandler;
 
-    private ColorStateList mDefaultColorState;
     private CharSequence mMessage;
-    private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
-    private boolean mBouncerShowing;
-    private boolean mAltBouncerShowing;
+    private boolean mIsVisible;
     /**
      * Container that wraps the KeyguardMessageArea - may be null if current view hierarchy doesn't
      * contain {@link R.id.keyguard_message_area_container}.
@@ -96,23 +89,11 @@
         mContainer.setLayoutParams(lp);
     }
 
-    @Override
-    public void setNextMessageColor(ColorStateList colorState) {
-        mNextMessageColorState = colorState;
-    }
-
-    void onThemeChanged() {
-        TypedArray array = mContext.obtainStyledAttributes(new int[] {
-                android.R.attr.textColorPrimary
-        });
-        ColorStateList newTextColors = ColorStateList.valueOf(array.getColor(0, Color.RED));
-        array.recycle();
-        mDefaultColorState = newTextColors;
+    protected void onThemeChanged() {
         update();
     }
 
-    void reloadColor() {
-        mDefaultColorState = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
+    protected void reloadColor() {
         update();
     }
 
@@ -151,17 +132,6 @@
         setMessage(message);
     }
 
-    public static KeyguardMessageArea findSecurityMessageDisplay(View v) {
-        KeyguardMessageArea messageArea = v.findViewById(R.id.keyguard_message_area);
-        if (messageArea == null) {
-            messageArea = v.getRootView().findViewById(R.id.keyguard_message_area);
-        }
-        if (messageArea == null) {
-            throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass());
-        }
-        return messageArea;
-    }
-
     private void securityMessageChanged(CharSequence message) {
         mMessage = message;
         update();
@@ -177,40 +147,23 @@
 
     void update() {
         CharSequence status = mMessage;
-        setVisibility(TextUtils.isEmpty(status) || (!mBouncerShowing && !mAltBouncerShowing)
-                ? INVISIBLE : VISIBLE);
+        setVisibility(TextUtils.isEmpty(status) || (!mIsVisible) ? INVISIBLE : VISIBLE);
         setText(status);
-        ColorStateList colorState = mDefaultColorState;
-        if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) {
-            colorState = mNextMessageColorState;
-            mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
-        }
-        if (mAltBouncerShowing) {
-            // alt bouncer has a black scrim, so always show the text in white
-            colorState = ColorStateList.valueOf(Color.WHITE);
-        }
-        setTextColor(colorState);
+        updateTextColor();
     }
 
     /**
      * Set whether the bouncer is fully showing
      */
-    public void setBouncerShowing(boolean bouncerShowing) {
-        if (mBouncerShowing != bouncerShowing) {
-            mBouncerShowing = bouncerShowing;
+    public void setIsVisible(boolean isVisible) {
+        if (mIsVisible != isVisible) {
+            mIsVisible = isVisible;
             update();
         }
     }
 
-    /**
-     * Set whether the alt bouncer is showing
-     */
-    void setAltBouncerShowing(boolean showing) {
-        if (mAltBouncerShowing != showing) {
-            mAltBouncerShowing = showing;
-            update();
-        }
-    }
+    /** Set the text color */
+    protected abstract void updateTextColor();
 
     /**
      * Runnable used to delay accessibility announcements.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 3ec8ce9..c2802f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -26,11 +26,14 @@
 
 import javax.inject.Inject;
 
-/** Controller for a {@link KeyguardMessageAreaController}. */
-public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> {
+/**
+ * Controller for a {@link KeyguardMessageAreaController}.
+ * @param <T> A subclass of KeyguardMessageArea.
+ */
+public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
+        extends ViewController<T> {
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ConfigurationController mConfigurationController;
-    private boolean mAltBouncerShowing;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
         public void onFinishedGoingToSleep(int why) {
@@ -59,7 +62,7 @@
         }
     };
 
-    private KeyguardMessageAreaController(KeyguardMessageArea view,
+    protected KeyguardMessageAreaController(T view,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             ConfigurationController configurationController) {
         super(view);
@@ -83,17 +86,10 @@
     }
 
     /**
-     * Set whether alt bouncer is showing
+     * Indicate that view is visible and can display messages.
      */
-    public void setAltBouncerShowing(boolean showing) {
-        mView.setAltBouncerShowing(showing);
-    }
-
-    /**
-     * Set bouncer is fully showing
-     */
-    public void setBouncerShowing(boolean showing) {
-        mView.setBouncerShowing(showing);
+    public void setIsVisible(boolean isVisible) {
+        mView.setIsVisible(isVisible);
     }
 
     public void setMessage(CharSequence s) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 6844b65..453072b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,23 +16,25 @@
 
 package com.android.keyguard;
 
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.View;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.constraintlayout.widget.ConstraintSet;
 
-import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
 
 /**
@@ -40,12 +42,15 @@
  */
 public class KeyguardPINView extends KeyguardPinBasedInputView {
 
-    private final AppearAnimationUtils mAppearAnimationUtils;
+    ValueAnimator mAppearAnimator = ValueAnimator.ofFloat(0f, 1f);
     private final DisappearAnimationUtils mDisappearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
     private ConstraintLayout mContainer;
     private int mDisappearYTranslation;
     private View[][] mViews;
+    private int mYTrans;
+    private int mYTransOffset;
+    private View mBouncerMessageView;
     @DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
 
     public KeyguardPINView(Context context) {
@@ -54,7 +59,6 @@
 
     public KeyguardPINView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mAppearAnimationUtils = new AppearAnimationUtils(context);
         mDisappearAnimationUtils = new DisappearAnimationUtils(context,
                 125, 0.6f /* translationScale */,
                 0.45f /* delayScale */, AnimationUtils.loadInterpolator(
@@ -66,6 +70,8 @@
                         mContext, android.R.interpolator.fast_out_linear_in));
         mDisappearYTranslation = getResources().getDimensionPixelSize(
                 R.dimen.disappear_y_translation);
+        mYTrans = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry);
+        mYTransOffset = getResources().getDimensionPixelSize(R.dimen.pin_view_trans_y_entry_offset);
     }
 
     @Override
@@ -137,6 +143,7 @@
         super.onFinishInflate();
 
         mContainer = findViewById(R.id.pin_container);
+        mBouncerMessageView = findViewById(R.id.bouncer_message_area);
         mViews = new View[][]{
                 new View[]{
                         findViewById(R.id.row0), null, null
@@ -169,25 +176,20 @@
 
     @Override
     public void startAppearAnimation() {
-        enableClipping(false);
-        setAlpha(1f);
-        setTranslationY(mAppearAnimationUtils.getStartTranslation());
-        AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
-                0, mAppearAnimationUtils.getInterpolator(),
-                getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
-        mAppearAnimationUtils.startAnimation2d(mViews,
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        enableClipping(true);
-                    }
-                });
+        if (mAppearAnimator.isRunning()) {
+            mAppearAnimator.cancel();
+        }
+        mAppearAnimator.setDuration(650);
+        mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+        mAppearAnimator.start();
     }
 
     public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
             final Runnable finishRunnable) {
+        if (mAppearAnimator.isRunning()) {
+            mAppearAnimator.cancel();
+        }
 
-        enableClipping(false);
         setTranslationY(0);
         DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
                         ? mDisappearAnimationUtilsLocked
@@ -195,7 +197,6 @@
         disappearAnimationUtils.createAnimation(
                 this, 0, 200, mDisappearYTranslation, false,
                 mDisappearAnimationUtils.getInterpolator(), () -> {
-                    enableClipping(true);
                     if (finishRunnable != null) {
                         finishRunnable.run();
                     }
@@ -204,14 +205,39 @@
         return true;
     }
 
-    private void enableClipping(boolean enable) {
-        mContainer.setClipToPadding(enable);
-        mContainer.setClipChildren(enable);
-        setClipChildren(enable);
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
+
+    /** Animate subviews according to expansion or time. */
+    private void animate(float progress) {
+        Interpolator standardDecelerate = Interpolators.STANDARD_DECELERATE;
+        Interpolator legacyDecelerate = Interpolators.LEGACY_DECELERATE;
+
+        mBouncerMessageView.setTranslationY(
+                mYTrans - mYTrans * standardDecelerate.getInterpolation(progress));
+
+        for (int i = 0; i < mViews.length; i++) {
+            View[] row = mViews[i];
+            for (View view : row) {
+                if (view == null) {
+                    continue;
+                }
+
+                float scaledProgress = legacyDecelerate.getInterpolation(MathUtils.constrain(
+                        (progress - 0.075f * i) / (1f - 0.075f * mViews.length),
+                        0f,
+                        1f
+                ));
+                view.setAlpha(scaledProgress);
+                int yDistance = mYTrans + mYTransOffset * i;
+                view.setTranslationY(
+                        yDistance - (yDistance * standardDecelerate.getInterpolation(progress)));
+                if (view instanceof NumPadAnimationListener) {
+                    ((NumPadAnimationListener) view).setProgress(scaledProgress);
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 1862fc7..afc2590 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -71,7 +71,7 @@
      */
     private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
 
-    KeyguardMessageArea mSecurityMessageDisplay;
+    BouncerKeyguardMessageArea mSecurityMessageDisplay;
     private View mEcaView;
     private ConstraintLayout mContainer;
 
@@ -120,7 +120,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
+        mSecurityMessageDisplay = findViewById(R.id.bouncer_message_area);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 9aa6f03..9871645 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -59,12 +59,9 @@
     private final LatencyTracker mLatencyTracker;
     private final FalsingCollector mFalsingCollector;
     private final EmergencyButtonController mEmergencyButtonController;
-    private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
     private final DevicePostureController mPostureController;
     private final DevicePostureController.Callback mPostureCallback =
             posture -> mView.onDevicePostureChanged(posture);
-
-    private KeyguardMessageAreaController mMessageAreaController;
     private LockPatternView mLockPatternView;
     private CountDownTimer mCountdownTimer;
     private AsyncTask<?, ?, ?> mPendingLockCheck;
@@ -201,15 +198,13 @@
             EmergencyButtonController emergencyButtonController,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             DevicePostureController postureController) {
-        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
+        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
+                messageAreaControllerFactory);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
         mFalsingCollector = falsingCollector;
         mEmergencyButtonController = emergencyButtonController;
-        mMessageAreaControllerFactory = messageAreaControllerFactory;
-        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
-        mMessageAreaController = mMessageAreaControllerFactory.create(kma);
         mLockPatternView = mView.findViewById(R.id.lockPatternView);
         mPostureController = postureController;
     }
@@ -217,7 +212,6 @@
     @Override
     public void onInit() {
         super.onInit();
-        mMessageAreaController.init();
     }
 
     @Override
@@ -346,6 +340,9 @@
 
     @Override
     public void showMessage(CharSequence message, ColorStateList colorState) {
+        if (mMessageAreaController == null) {
+            return;
+        }
         if (colorState != null) {
             mMessageAreaController.setNextMessageColor(colorState);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 9f4585f..89fcc47 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -82,6 +82,12 @@
     }
 
     @Override
+    public void startAppearAnimation() {
+        mMessageAreaController.setMessageIfEmpty(R.string.keyguard_enter_your_pin);
+        super.startAppearAnimation();
+    }
+
+    @Override
     public boolean startDisappearAnimation(Runnable finishRunnable) {
         return mView.startDisappearAnimation(
                 mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index d0baf3d..f73c98e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -665,7 +665,8 @@
                 // When using EXACTLY spec, measure will use the layout width if > 0. Set before
                 // measuring the child
                 lp.width = MeasureSpec.getSize(updatedWidthMeasureSpec);
-                measureChildWithMargins(view, updatedWidthMeasureSpec, 0, heightMeasureSpec, 0);
+                measureChildWithMargins(view, updatedWidthMeasureSpec, 0,
+                        heightMeasureSpec, 0);
 
                 maxWidth = Math.max(maxWidth,
                         view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
@@ -1306,7 +1307,6 @@
             int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans);
             if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                 mUserSwitcherViewGroup.setTranslationY(yTrans);
-                mViewFlipper.setTranslationY(-yTrans);
             } else {
                 // Attempt to reposition a bit higher to make up for this frame being a bit lower
                 // on the device
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 3aa5ada..bddf4b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -146,7 +146,8 @@
         protected NullKeyguardInputViewController(SecurityMode securityMode,
                 KeyguardSecurityCallback keyguardSecurityCallback,
                 EmergencyButtonController emergencyButtonController) {
-            super(null, securityMode, keyguardSecurityCallback, emergencyButtonController);
+            super(null, securityMode, keyguardSecurityCallback, emergencyButtonController,
+                    null);
         }
 
         @Override
@@ -156,7 +157,6 @@
 
         @Override
         public void onStartingToHide() {
-
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt
new file mode 100644
index 0000000..b4bfca1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import androidx.core.graphics.drawable.DrawableCompat
+import com.android.systemui.R
+
+abstract class KeyguardSimInputView(context: Context, attrs: AttributeSet) :
+    KeyguardPinBasedInputView(context, attrs) {
+    private var simImageView: ImageView? = null
+    private var disableESimButton: KeyguardEsimArea? = null
+
+    override fun onFinishInflate() {
+        simImageView = findViewById(R.id.keyguard_sim)
+        disableESimButton = findViewById(R.id.keyguard_esim_area)
+        super.onFinishInflate()
+    }
+
+    /** Set UI state based on whether there is a locked eSim card */
+    fun setESimLocked(isESimLocked: Boolean, subId: Int) {
+        disableESimButton?.setSubscriptionId(subId)
+        disableESimButton?.visibility = if (isESimLocked) VISIBLE else GONE
+        simImageView?.visibility = if (isESimLocked) GONE else VISIBLE
+    }
+
+    override fun reloadColors() {
+        super.reloadColors()
+        val customAttrs = intArrayOf(android.R.attr.textColorSecondary)
+        val a = context.obtainStyledAttributes(customAttrs)
+        val imageColor = a.getColor(0, 0)
+        a.recycle()
+        simImageView?.let {
+            val wrappedDrawable = DrawableCompat.wrap(it.drawable)
+            DrawableCompat.setTint(wrappedDrawable, imageColor)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index ae9d3df..9d17015 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -18,21 +18,14 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.core.graphics.drawable.DrawableCompat;
 
 import com.android.systemui.R;
 
 /**
  * Displays a PIN pad for unlocking.
  */
-public class KeyguardSimPinView extends KeyguardPinBasedInputView {
-    private ImageView mSimImageView;
+public class KeyguardSimPinView extends KeyguardSimInputView {
     public static final String TAG = "KeyguardSimPinView";
 
     public KeyguardSimPinView(Context context) {
@@ -43,12 +36,6 @@
         super(context, attrs);
     }
 
-    public void setEsimLocked(boolean locked, int subscriptionId) {
-        KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
-        esimButton.setSubscriptionId(subscriptionId);
-        esimButton.setVisibility(locked ? View.VISIBLE : View.GONE);
-    }
-
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -68,7 +55,6 @@
 
     @Override
     protected void onFinishInflate() {
-        mSimImageView = findViewById(R.id.keyguard_sim);
         super.onFinishInflate();
 
         if (mEcaView instanceof EmergencyCarrierArea) {
@@ -86,17 +72,4 @@
         return getContext().getString(
                 com.android.internal.R.string.keyguard_accessibility_sim_pin_unlock);
     }
-
-    @Override
-    public void reloadColors() {
-        super.reloadColors();
-
-        int[] customAttrs = {android.R.attr.textColorSecondary};
-        TypedArray a = getContext().obtainStyledAttributes(customAttrs);
-        int imageColor = a.getColor(0, 0);
-        a.recycle();
-        Drawable wrappedDrawable = DrawableCompat.wrap(mSimImageView.getDrawable());
-        DrawableCompat.setTint(wrappedDrawable, imageColor);
-    }
 }
-
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 2a2e9bf..91bf20f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -105,7 +105,7 @@
             showDefaultMessage();
         }
 
-        mView.setEsimLocked(KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId), mSubId);
+        mView.setESimLocked(KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId), mSubId);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index c0971bf..5f45fe3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -19,13 +19,8 @@
 import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
 
 import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.widget.ImageView;
-
-import androidx.core.graphics.drawable.DrawableCompat;
 
 import com.android.systemui.R;
 
@@ -33,8 +28,7 @@
 /**
  * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
  */
-public class KeyguardSimPukView extends KeyguardPinBasedInputView {
-    private ImageView mSimImageView;
+public class KeyguardSimPukView extends KeyguardSimInputView {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     public static final String TAG = "KeyguardSimPukView";
 
@@ -86,7 +80,6 @@
 
     @Override
     protected void onFinishInflate() {
-        mSimImageView = findViewById(R.id.keyguard_sim);
         super.onFinishInflate();
 
         if (mEcaView instanceof EmergencyCarrierArea) {
@@ -104,18 +97,4 @@
         return getContext().getString(
                 com.android.internal.R.string.keyguard_accessibility_sim_puk_unlock);
     }
-
-    @Override
-    public void reloadColors() {
-        super.reloadColors();
-
-        int[] customAttrs = {android.R.attr.textColorSecondary};
-        TypedArray a = getContext().obtainStyledAttributes(customAttrs);
-        int imageColor = a.getColor(0, 0);
-        a.recycle();
-        Drawable wrappedDrawable = DrawableCompat.wrap(mSimImageView.getDrawable());
-        DrawableCompat.setTint(wrappedDrawable, imageColor);
-    }
 }
-
-
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 203f9b6..d8cffd7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -30,7 +30,6 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
-import android.view.View;
 import android.view.WindowManager;
 import android.widget.ImageView;
 
@@ -173,11 +172,9 @@
             if (mShowDefaultMessage) {
                 showDefaultMessage();
             }
-            boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
 
-            KeyguardEsimArea esimButton = mView.findViewById(R.id.keyguard_esim_area);
-            esimButton.setSubscriptionId(mSubId);
-            esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
+            mView.setESimLocked(KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId), mSubId);
+
             mPasswordEntry.requestFocus();
         }
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index acbea1b..7d6f377 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -50,12 +50,10 @@
             viewsIdToTranslate =
                 setOf(
                     ViewIdToTranslate(R.id.keyguard_status_area, LEFT, filterNever),
-                    ViewIdToTranslate(R.id.controls_button, LEFT, filterNever),
                     ViewIdToTranslate(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
                     ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
                     ViewIdToTranslate(
                         R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
-                    ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever),
                     ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
                     ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
             progressProvider = unfoldProgressProvider)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 094c4a7..7e04f04 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,6 +26,7 @@
 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT;
 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
 import static android.hardware.biometrics.BiometricConstants.LockoutMode;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
@@ -104,8 +105,10 @@
 import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -154,6 +157,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -164,6 +168,7 @@
 import java.util.TimeZone;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -263,6 +268,7 @@
     private final AuthController mAuthController;
     private final StatusBarStateController mStatusBarStateController;
     private final UiEventLogger mUiEventLogger;
+    private final Set<Integer> mFaceAcquiredInfoIgnoreList;
     private int mStatusBarState;
     private final StatusBarStateController.StateListener mStatusBarStateControllerListener =
             new StatusBarStateController.StateListener() {
@@ -341,6 +347,8 @@
     private final Executor mBackgroundExecutor;
     private SensorPrivacyManager mSensorPrivacyManager;
     private final ActiveUnlockConfig mActiveUnlockConfig;
+    private final PowerManager mPowerManager;
+    private final boolean mWakeOnFingerprintAcquiredStart;
 
     /**
      * Short delay before restarting fingerprint authentication after a successful try. This should
@@ -451,6 +459,7 @@
                     FACE_AUTH_TRIGGERED_TRUST_DISABLED);
         }
 
+        mLogger.logTrustChanged(wasTrusted, enabled, userId);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -466,12 +475,16 @@
             final boolean userHasTrust = getUserHasTrust(userId);
             if (userHasTrust && trustGrantedMessages != null) {
                 for (String msg : trustGrantedMessages) {
-                    if (!TextUtils.isEmpty(msg)) {
-                        message = msg;
+                    message = msg;
+                    if (!TextUtils.isEmpty(message)) {
                         break;
                     }
                 }
             }
+
+            if (message != null) {
+                mLogger.logShowTrustGrantedMessage(message.toString());
+            }
             for (int i = 0; i < mCallbacks.size(); i++) {
                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                 if (cb != null) {
@@ -728,6 +741,7 @@
         mFingerprintCancelSignal = null;
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_FP_AUTHENTICATED);
+        mLogger.d("onFingerprintAuthenticated");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -784,6 +798,11 @@
     private void handleFingerprintAcquired(
             @BiometricFingerprintConstants.FingerprintAcquired int acquireInfo) {
         Assert.isMainThread();
+        if (mWakeOnFingerprintAcquiredStart && acquireInfo == FINGERPRINT_ACQUIRED_START) {
+            mPowerManager.wakeUp(
+                    SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+                    "com.android.systemui.keyguard:FINGERPRINT_ACQUIRED_START");
+        }
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -971,6 +990,7 @@
         mFaceCancelSignal = null;
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED);
+        mLogger.d("onFaceAuthenticated");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -991,6 +1011,7 @@
 
     private void handleFaceAuthFailed() {
         Assert.isMainThread();
+        mLogger.d("onFaceAuthFailed");
         mFaceCancelSignal = null;
         setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         for (int i = 0; i < mCallbacks.size(); i++) {
@@ -1607,6 +1628,9 @@
 
                 @Override
                 public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+                    if (mFaceAcquiredInfoIgnoreList.contains(helpMsgId)) {
+                        return;
+                    }
                     handleFaceHelp(helpMsgId, helpString.toString());
                 }
 
@@ -1873,7 +1897,8 @@
             KeyguardUpdateMonitorLogger logger,
             UiEventLogger uiEventLogger,
             // This has to be a provider because SessionTracker depends on KeyguardUpdateMonitor :(
-            Provider<SessionTracker> sessionTrackerProvider) {
+            Provider<SessionTracker> sessionTrackerProvider,
+            PowerManager powerManager) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
         mTelephonyListenerManager = telephonyListenerManager;
@@ -1894,7 +1919,15 @@
         mLogger = logger;
         mUiEventLogger = uiEventLogger;
         mSessionTrackerProvider = sessionTrackerProvider;
+        mPowerManager = powerManager;
         mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
+        mWakeOnFingerprintAcquiredStart = context.getResources()
+                        .getBoolean(com.android.internal.R.bool.kg_wake_on_acquire_start);
+        mFaceAcquiredInfoIgnoreList = Arrays.stream(
+                mContext.getResources().getIntArray(
+                        R.array.config_face_acquire_device_entry_ignorelist))
+                .boxed()
+                .collect(Collectors.toSet());
 
         mHandler = new Handler(mainLooper) {
             @Override
@@ -2591,6 +2624,7 @@
         final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
         final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
         final boolean onlyFaceEnrolled = isOnlyFaceEnrolled();
+        final boolean fpOrFaceIsLockedOut = isFaceLockedOut() || fpLockedout;
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -2607,7 +2641,7 @@
                 && strongAuthAllowsScanning && mIsPrimaryUser
                 && (!mSecureCameraLaunched || mOccludingAppRequestingFace)
                 && !faceAuthenticated
-                && !fpLockedout;
+                && !fpOrFaceIsLockedOut;
 
         // Aggregate relevant fields for debug logging.
         maybeLogListenerModelData(
@@ -2622,6 +2656,8 @@
                     mBouncerIsOrWillBeShowing,
                     faceAuthenticated,
                     faceDisabledForUser,
+                    isFaceLockedOut(),
+                    fpLockedout,
                     mGoingToSleep,
                     awakeKeyguardExcludingBouncerShowing,
                     mKeyguardGoingAway,
@@ -3431,6 +3467,7 @@
         mUserFaceAuthenticated.clear();
         mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT, unlockedUser);
         mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, unlockedUser);
+        mLogger.d("clearBiometricRecognized");
 
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -3680,6 +3717,10 @@
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println("KeyguardUpdateMonitor state:");
+        pw.println("  getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
+        pw.println("  getUserUnlockedWithBiometric()="
+                + getUserUnlockedWithBiometric(getCurrentUser()));
+        pw.println("  mWakeOnFingerprintAcquiredStart=" + mWakeOnFingerprintAcquiredStart);
         pw.println("  SIM States:");
         for (SimData data : mSimDatas.values()) {
             pw.println("    " + data.toString());
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
index 1de740a..f449edf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,15 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.keyguard
 
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
+/** Interface for classes to track animation progress. */
+interface NumPadAnimationListener {
+    /** Track the progress of the animation. */
+    fun setProgress(progress: Float)
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index c91c899..41111e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -48,6 +48,10 @@
     private int mTextColorPrimary;
     private int mTextColorPressed;
     private int mStyle;
+    private float mStartRadius;
+    private float mEndRadius;
+    private int mHeight;
+
     private static final int EXPAND_ANIMATION_MS = 100;
     private static final int EXPAND_COLOR_ANIMATION_MS = 50;
     private static final int CONTRACT_ANIMATION_DELAY_MS = 33;
@@ -80,12 +84,20 @@
         mContractAnimatorSet.start();
     }
 
+    public void setProgress(float progress) {
+        mBackground.setCornerRadius(mEndRadius + (mStartRadius - mEndRadius) * progress);
+        int height = (int) (mHeight * 0.7f + mHeight * 0.3 * progress);
+        int difference = mHeight - height;
+        mBackground.setBounds(0, difference / 2, mHeight, mHeight - difference / 2);
+    }
+
     void onLayout(int height) {
-        float startRadius = height / 2f;
-        float endRadius = height / 4f;
-        mBackground.setCornerRadius(startRadius);
-        mExpandAnimator.setFloatValues(startRadius, endRadius);
-        mContractAnimator.setFloatValues(endRadius, startRadius);
+        mHeight = height;
+        mStartRadius = height / 2f;
+        mEndRadius = height / 4f;
+        mBackground.setCornerRadius(mStartRadius);
+        mExpandAnimator.setFloatValues(mStartRadius, mEndRadius);
+        mContractAnimator.setFloatValues(mEndRadius, mStartRadius);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 8099f75..37060987c 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -30,7 +30,7 @@
 /**
  * Similar to the {@link NumPadKey}, but displays an image.
  */
-public class NumPadButton extends AlphaOptimizedImageButton {
+public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAnimationListener {
 
     @Nullable
     private NumPadAnimator mAnimator;
@@ -104,4 +104,11 @@
         a.recycle();
         ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
     }
+
+    @Override
+    public void setProgress(float progress) {
+        if (mAnimator != null) {
+            mAnimator.setProgress(progress);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 4aed251..0a4880e 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -37,7 +37,10 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
-public class NumPadKey extends ViewGroup {
+/**
+ * Viewgroup for the bouncer numpad button, specifically for digits.
+ */
+public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
     // list of "ABC", etc per digit, starting with '0'
     static String sKlondike[];
 
@@ -221,4 +224,11 @@
         performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
     }
+
+    @Override
+    public void setProgress(float progress) {
+        if (mAnimator != null) {
+            mAnimator.setProgress(progress);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java b/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
index 7c86a1d..777bd19 100644
--- a/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
+++ b/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
@@ -20,7 +20,8 @@
 
 public interface SecurityMessageDisplay {
 
-    void setNextMessageColor(ColorStateList colorState);
+    /** Set text color for the next security message. */
+    default void setNextMessageColor(ColorStateList colorState) {}
 
     void setMessage(CharSequence msg);
 
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
new file mode 100644
index 0000000..2c2ab7b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard.logging
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.dagger.BiometricMessagesLog
+import javax.inject.Inject
+
+/** Helper class for logging for [com.android.systemui.biometrics.FaceHelpMessageDeferral] */
+@SysUISingleton
+class FaceMessageDeferralLogger
+@Inject
+constructor(@BiometricMessagesLog private val logBuffer: LogBuffer) :
+    BiometricMessageDeferralLogger(logBuffer, "FaceMessageDeferralLogger")
+
+open class BiometricMessageDeferralLogger(
+    private val logBuffer: LogBuffer,
+    private val tag: String
+) {
+    fun reset() {
+        logBuffer.log(tag, DEBUG, "reset")
+    }
+
+    fun logUpdateMessage(acquiredInfo: Int, helpString: String) {
+        logBuffer.log(
+            tag,
+            DEBUG,
+            {
+                int1 = acquiredInfo
+                str1 = helpString
+            },
+            { "updateMessage acquiredInfo=$int1 helpString=$str1" }
+        )
+    }
+
+    fun logFrameProcessed(
+        acquiredInfo: Int,
+        totalFrames: Int,
+        mostFrequentAcquiredInfoToDefer: String? // may not meet the threshold
+    ) {
+        logBuffer.log(
+            tag,
+            DEBUG,
+            {
+                int1 = acquiredInfo
+                int2 = totalFrames
+                str1 = mostFrequentAcquiredInfoToDefer
+            },
+            {
+                "frameProcessed acquiredInfo=$int1 totalFrames=$int2 " +
+                    "messageToShowOnTimeout=$str1"
+            }
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 2bc98f1..7a00cd9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -340,4 +340,40 @@
                     bool1 = dismissKeyguard
                 }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
     }
+
+    fun logShowTrustGrantedMessage(
+            message: String
+    ) {
+        logBuffer.log(TAG, DEBUG, {
+            str1 = message
+        }, { "showTrustGrantedMessage message$str1" })
+    }
+
+    fun logTrustChanged(
+            wasTrusted: Boolean,
+            isNowTrusted: Boolean,
+            userId: Int
+    ) {
+        logBuffer.log(TAG, DEBUG, {
+            bool1 = wasTrusted
+            bool2 = isNowTrusted
+            int1 = userId
+        }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+    }
+
+    fun logKeyguardStateUpdate(
+            secure: Boolean,
+            canDismissLockScreen: Boolean,
+            trusted: Boolean,
+            trustManaged: Boolean
+
+    ) {
+        logBuffer.log("KeyguardState", DEBUG, {
+            bool1 = secure
+            bool2 = canDismissLockScreen
+            bool3 = trusted
+            bool4 = trustManaged
+        }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
+                " trusted=$bool3 trustManaged=$bool4" })
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 9138b23..9cfd399 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui;
 
-import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.app.Notification;
@@ -29,7 +28,6 @@
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -130,13 +128,6 @@
                         ThreadedRenderer.EGL_CONTEXT_PRIORITY_HIGH_IMG);
             }
 
-            // Enable binder tracing on system server for calls originating from SysUI
-            try {
-                ActivityManager.getService().enableBinderTracing();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Unable to enable binder tracing", e);
-            }
-
             registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 813f4dd..e3c04a3 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -62,6 +62,7 @@
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.WindowMetrics;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -75,7 +76,6 @@
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.R;
 import com.android.systemui.model.SysUiState;
-import com.android.systemui.shared.system.WindowManagerWrapper;
 
 import java.io.PrintWriter;
 import java.text.NumberFormat;
@@ -689,7 +689,7 @@
         if (Float.isNaN(centerX)) {
             centerX = mMagnificationFrame.centerX();
         }
-        if (Float.isNaN(centerX)) {
+        if (Float.isNaN(centerY)) {
             centerY = mMagnificationFrame.centerY();
         }
 
@@ -723,7 +723,7 @@
      * child of the surfaceView.
      */
     private void createMirror() {
-        mMirrorSurface = WindowManagerWrapper.getInstance().mirrorDisplay(mDisplayId);
+        mMirrorSurface = mirrorDisplay(mDisplayId);
         if (!mMirrorSurface.isValid()) {
             return;
         }
@@ -732,6 +732,25 @@
         modifyWindowMagnification(false);
     }
 
+    /**
+     * Mirrors a specified display. The SurfaceControl returned is the root of the mirrored
+     * hierarchy.
+     *
+     * @param displayId The id of the display to mirror
+     * @return The SurfaceControl for the root of the mirrored hierarchy.
+     */
+    private SurfaceControl mirrorDisplay(final int displayId) {
+        try {
+            SurfaceControl outSurfaceControl = new SurfaceControl();
+            WindowManagerGlobal.getWindowManagerService().mirrorDisplay(displayId,
+                    outSurfaceControl);
+            return outSurfaceControl;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to reach window manager", e);
+        }
+        return null;
+    }
+
     private void addDragTouchListeners() {
         mDragView = mMirrorView.findViewById(R.id.drag_handle);
         mLeftDrag = mMirrorView.findViewById(R.id.left_handle);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index 40d1eff..e4c197f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -29,8 +29,9 @@
 /** Face/Fingerprint combined icon animator for BiometricPrompt. */
 class AuthBiometricFingerprintAndFaceIconController(
         context: Context,
-        iconView: LottieAnimationView
-) : AuthBiometricFingerprintIconController(context, iconView) {
+        iconView: LottieAnimationView,
+        iconViewOverlay: LottieAnimationView
+) : AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay) {
 
     override val actsAsConfirmButton: Boolean = true
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
index 7371442..7f5a67f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
@@ -39,5 +39,5 @@
     override fun onPointerDown(failedModalities: Set<Int>) = failedModalities.contains(TYPE_FACE)
 
     override fun createIconController(): AuthIconController =
-        AuthBiometricFingerprintAndFaceIconController(mContext, mIconView)
+        AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 9b5f54a..b40b356 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -18,7 +18,12 @@
 
 import android.annotation.RawRes
 import android.content.Context
+import android.hardware.fingerprint.FingerprintManager
+import android.view.DisplayInfo
+import android.view.Surface
+import android.view.View
 import com.airbnb.lottie.LottieAnimationView
+import com.android.settingslib.widget.LottieColorUtils
 import com.android.systemui.R
 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
 import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
@@ -32,14 +37,18 @@
 /** Fingerprint only icon animator for BiometricPrompt.  */
 open class AuthBiometricFingerprintIconController(
         context: Context,
-        iconView: LottieAnimationView
+        iconView: LottieAnimationView,
+        protected val iconViewOverlay: LottieAnimationView
 ) : AuthIconController(context, iconView) {
 
+    private val isSideFps: Boolean
     var iconLayoutParamSize: Pair<Int, Int> = Pair(1, 1)
         set(value) {
             if (field == value) {
                 return
             }
+            iconViewOverlay.layoutParams.width = value.first
+            iconViewOverlay.layoutParams.height = value.second
             iconView.layoutParams.width = value.first
             iconView.layoutParams.height = value.second
             field = value
@@ -50,9 +59,53 @@
                 R.dimen.biometric_dialog_fingerprint_icon_width),
                 context.resources.getDimensionPixelSize(
                         R.dimen.biometric_dialog_fingerprint_icon_height))
+        var sideFps = false
+        (context.getSystemService(Context.FINGERPRINT_SERVICE)
+                as FingerprintManager?)?.let { fpm ->
+            for (prop in fpm.sensorPropertiesInternal) {
+                if (prop.isAnySidefpsType) {
+                    sideFps = true
+                }
+            }
+        }
+        isSideFps = sideFps
+        val displayInfo = DisplayInfo()
+        context.display?.getDisplayInfo(displayInfo)
+        if (isSideFps && displayInfo.rotation == Surface.ROTATION_180) {
+            iconView.rotation = 180f
+        }
     }
 
-    override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+    private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) {
+        val displayInfo = DisplayInfo()
+        context.display?.getDisplayInfo(displayInfo)
+        val rotation = displayInfo.rotation
+        val iconAnimation = getSideFpsAnimationForTransition(rotation)
+        val iconViewOverlayAnimation =
+                getSideFpsOverlayAnimationForTransition(lastState, newState, rotation) ?: return
+
+        if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
+            iconView.setAnimation(iconAnimation)
+            iconViewOverlay.setAnimation(iconViewOverlayAnimation)
+        }
+
+        val iconContentDescription = getIconContentDescription(newState)
+        if (iconContentDescription != null) {
+            iconView.contentDescription = iconContentDescription
+            iconViewOverlay.contentDescription = iconContentDescription
+        }
+
+        iconView.frame = 0
+        iconViewOverlay.frame = 0
+        if (shouldAnimateForTransition(lastState, newState)) {
+            iconView.playAnimation()
+            iconViewOverlay.playAnimation()
+        }
+        LottieColorUtils.applyDynamicColors(context, iconView)
+        LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
+    }
+
+    private fun updateIconNormal(@BiometricState lastState: Int, @BiometricState newState: Int) {
         val icon = getAnimationForTransition(lastState, newState) ?: return
 
         if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
@@ -68,6 +121,16 @@
         if (shouldAnimateForTransition(lastState, newState)) {
             iconView.playAnimation()
         }
+        LottieColorUtils.applyDynamicColors(context, iconView)
+    }
+
+    override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+        if (isSideFps) {
+            updateIconSideFps(lastState, newState)
+        } else {
+            iconViewOverlay.visibility = View.GONE
+            updateIconNormal(lastState, newState)
+        }
     }
 
     private fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
@@ -125,4 +188,89 @@
         }
         return if (id != null) return id else null
     }
+
+    @RawRes
+    private fun getSideFpsAnimationForTransition(rotation: Int): Int = when (rotation) {
+        Surface.ROTATION_0 -> R.raw.biometricprompt_landscape_base
+        Surface.ROTATION_90 -> R.raw.biometricprompt_portrait_base_topleft
+        Surface.ROTATION_180 -> R.raw.biometricprompt_landscape_base
+        Surface.ROTATION_270 -> R.raw.biometricprompt_portrait_base_bottomright
+        else -> R.raw.biometricprompt_landscape_base
+    }
+
+    @RawRes
+    private fun getSideFpsOverlayAnimationForTransition(
+            @BiometricState oldState: Int,
+            @BiometricState newState: Int,
+            rotation: Int
+    ): Int? = when (newState) {
+        STATE_HELP,
+        STATE_ERROR -> {
+            when (rotation) {
+                Surface.ROTATION_0 -> R.raw.biometricprompt_fingerprint_to_error_landscape
+                Surface.ROTATION_90 ->
+                    R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft
+                Surface.ROTATION_180 ->
+                    R.raw.biometricprompt_fingerprint_to_error_landscape
+                Surface.ROTATION_270 ->
+                    R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright
+                else -> R.raw.biometricprompt_fingerprint_to_error_landscape
+            }
+        }
+        STATE_AUTHENTICATING_ANIMATING_IN,
+        STATE_AUTHENTICATING -> {
+            if (oldState == STATE_ERROR || oldState == STATE_HELP) {
+                when (rotation) {
+                    Surface.ROTATION_0 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_bottomright
+                    else -> R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+                }
+            } else {
+                when (rotation) {
+                    Surface.ROTATION_0 -> R.raw.biometricprompt_fingerprint_to_error_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_fingerprint_to_error_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright
+                    else -> R.raw.biometricprompt_fingerprint_to_error_landscape
+                }
+            }
+        }
+        STATE_AUTHENTICATED -> {
+            if (oldState == STATE_ERROR || oldState == STATE_HELP) {
+                when (rotation) {
+                    Surface.ROTATION_0 ->
+                        R.raw.biometricprompt_symbol_error_to_success_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_error_to_success_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_symbol_error_to_success_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_error_to_success_portrait_bottomright
+                    else -> R.raw.biometricprompt_symbol_error_to_success_landscape
+                }
+            } else {
+                when (rotation) {
+                    Surface.ROTATION_0 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_bottomright
+                    else -> R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+                }
+            }
+        }
+        else -> null
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 9cce066..2066634 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -86,7 +86,7 @@
     override fun supportsSmallDialog() = false
 
     override fun createIconController(): AuthIconController =
-        AuthBiometricFingerprintIconController(mContext, mIconView)
+        AuthBiometricFingerprintIconController(mContext, mIconView, mIconViewOverlay)
 
     fun updateOverrideIconLayoutParamsSize() {
         udfpsAdapter?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index fc5cf9f..0ac71c4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -133,6 +133,7 @@
     private TextView mSubtitleView;
     private TextView mDescriptionView;
     private View mIconHolderView;
+    protected LottieAnimationView mIconViewOverlay;
     protected LottieAnimationView mIconView;
     protected TextView mIndicatorView;
 
@@ -168,6 +169,10 @@
 
     private Animator.AnimatorListener mJankListener;
 
+    private final boolean mUseCustomBpSize;
+    private final int mCustomBpWidth;
+    private final int mCustomBpHeight;
+
     private final OnClickListener mBackgroundClickListener = (view) -> {
         if (mState == STATE_AUTHENTICATED) {
             Log.w(TAG, "Ignoring background click after authenticated");
@@ -208,6 +213,10 @@
             handleResetAfterHelp();
             Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
         };
+
+        mUseCustomBpSize = getResources().getBoolean(R.bool.use_custom_bp_size);
+        mCustomBpWidth = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_width);
+        mCustomBpHeight = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_height);
     }
 
     /** Delay after authentication is confirmed, before the dialog should be animated away. */
@@ -651,6 +660,7 @@
         mTitleView = findViewById(R.id.title);
         mSubtitleView = findViewById(R.id.subtitle);
         mDescriptionView = findViewById(R.id.description);
+        mIconViewOverlay = findViewById(R.id.biometric_icon_overlay);
         mIconView = findViewById(R.id.biometric_icon);
         mIconHolderView = findViewById(R.id.biometric_icon_frame);
         mIndicatorView = findViewById(R.id.indicator);
@@ -689,6 +699,11 @@
 
         mIconController = createIconController();
         if (mIconController.getActsAsConfirmButton()) {
+            mIconViewOverlay.setOnClickListener((view)->{
+                if (mState == STATE_PENDING_CONFIRMATION) {
+                    updateState(STATE_AUTHENTICATED);
+                }
+            });
             mIconView.setOnClickListener((view) -> {
                 if (mState == STATE_PENDING_CONFIRMATION) {
                     updateState(STATE_AUTHENTICATED);
@@ -827,14 +842,17 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int width = MeasureSpec.getSize(widthMeasureSpec);
-        final int height = MeasureSpec.getSize(heightMeasureSpec);
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int height = MeasureSpec.getSize(heightMeasureSpec);
 
-        final int newWidth = Math.min(width, height);
+        if (mUseCustomBpSize) {
+            width = mCustomBpWidth;
+            height = mCustomBpHeight;
+        } else {
+            width = Math.min(width, height);
+        }
 
-        // Use "newWidth" instead, so the landscape dialog width is the same as the portrait
-        // width.
-        mLayoutParams = onMeasureInternal(newWidth, height);
+        mLayoutParams = onMeasureInternal(width, height);
         setMeasuredDimension(mLayoutParams.mMediumWidth, mLayoutParams.mMediumHeight);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
new file mode 100644
index 0000000..fabc1c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.content.res.Resources
+import com.android.keyguard.logging.BiometricMessageDeferralLogger
+import com.android.keyguard.logging.FaceMessageDeferralLogger
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import java.io.PrintWriter
+import java.util.*
+import javax.inject.Inject
+
+/**
+ * Provides whether a face acquired help message should be shown immediately when its received or
+ * should be shown when face auth times out. See [updateMessage] and [getDeferredMessage].
+ */
+@SysUISingleton
+class FaceHelpMessageDeferral
+@Inject
+constructor(
+    @Main resources: Resources,
+    logBuffer: FaceMessageDeferralLogger,
+    dumpManager: DumpManager
+) :
+    BiometricMessageDeferral(
+        resources.getIntArray(R.array.config_face_help_msgs_defer_until_timeout).toHashSet(),
+        resources.getFloat(R.dimen.config_face_help_msgs_defer_until_timeout_threshold),
+        logBuffer,
+        dumpManager
+    )
+
+/**
+ * @property messagesToDefer messages that shouldn't show immediately when received, but may be
+ * shown later if the message is the most frequent acquiredInfo processed and meets [threshold]
+ * percentage of all passed acquired frames.
+ */
+open class BiometricMessageDeferral(
+    private val messagesToDefer: Set<Int>,
+    private val threshold: Float,
+    private val logBuffer: BiometricMessageDeferralLogger,
+    dumpManager: DumpManager
+) : Dumpable {
+    private val acquiredInfoToFrequency: MutableMap<Int, Int> = HashMap()
+    private val acquiredInfoToHelpString: MutableMap<Int, String> = HashMap()
+    private var mostFrequentAcquiredInfoToDefer: Int? = null
+    private var totalFrames = 0
+
+    init {
+        dumpManager.registerDumpable(this.javaClass.name, this)
+    }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println("messagesToDefer=$messagesToDefer")
+        pw.println("totalFrames=$totalFrames")
+        pw.println("threshold=$threshold")
+    }
+
+    /** Reset all saved counts. */
+    fun reset() {
+        totalFrames = 0
+        mostFrequentAcquiredInfoToDefer = null
+        acquiredInfoToFrequency.clear()
+        acquiredInfoToHelpString.clear()
+        logBuffer.reset()
+    }
+
+    /** Updates the message associated with the acquiredInfo if it's a message we may defer. */
+    fun updateMessage(acquiredInfo: Int, helpString: String) {
+        if (!messagesToDefer.contains(acquiredInfo)) {
+            return
+        }
+        if (!Objects.equals(acquiredInfoToHelpString[acquiredInfo], helpString)) {
+            logBuffer.logUpdateMessage(acquiredInfo, helpString)
+            acquiredInfoToHelpString[acquiredInfo] = helpString
+        }
+    }
+
+    /** Whether the given message should be deferred instead of being shown immediately. */
+    fun shouldDefer(acquiredMsgId: Int): Boolean {
+        return messagesToDefer.contains(acquiredMsgId)
+    }
+
+    /** Adds the acquiredInfo frame to the counts. We account for all frames. */
+    fun processFrame(acquiredInfo: Int) {
+        if (messagesToDefer.isEmpty()) {
+            return
+        }
+
+        totalFrames++
+
+        val newAcquiredInfoCount = acquiredInfoToFrequency.getOrDefault(acquiredInfo, 0) + 1
+        acquiredInfoToFrequency[acquiredInfo] = newAcquiredInfoCount
+        if (
+            messagesToDefer.contains(acquiredInfo) &&
+                (mostFrequentAcquiredInfoToDefer == null ||
+                    newAcquiredInfoCount >
+                        acquiredInfoToFrequency.getOrDefault(mostFrequentAcquiredInfoToDefer!!, 0))
+        ) {
+            mostFrequentAcquiredInfoToDefer = acquiredInfo
+        }
+
+        logBuffer.logFrameProcessed(
+            acquiredInfo,
+            totalFrames,
+            mostFrequentAcquiredInfoToDefer?.toString()
+        )
+    }
+
+    /**
+     * Get the most frequent deferred message that meets the [threshold] percentage of processed
+     * frames.
+     * @return null if no acquiredInfo have been deferred OR deferred messages didn't meet the
+     * [threshold] percentage.
+     */
+    fun getDeferredMessage(): CharSequence? {
+        mostFrequentAcquiredInfoToDefer?.let {
+            if (acquiredInfoToFrequency.getOrDefault(it, 0) > (threshold * totalFrames)) {
+                return acquiredInfoToHelpString[it]
+            }
+        }
+        return null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index d96476f..49e378e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -99,11 +99,12 @@
         mProgressColor = context.getColor(R.color.udfps_enroll_progress);
         final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
         mIsAccessibilityEnabled = am.isTouchExplorationEnabled();
-        mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
         if (!mIsAccessibilityEnabled) {
             mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
+            mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
         } else {
             mHelpColor = context.getColor(R.color.udfps_enroll_progress_help_with_talkback);
+            mOnFirstBucketFailedColor = mHelpColor;
         }
         mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
         mCheckmarkDrawable.mutate();
@@ -166,8 +167,7 @@
     }
 
     private void updateProgress(int remainingSteps, int totalSteps, boolean showingHelp) {
-        if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps
-                && mShowingHelp == showingHelp) {
+        if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
             return;
         }
 
@@ -197,7 +197,6 @@
             }
         }
 
-        mShowingHelp = showingHelp;
         mRemainingSteps = remainingSteps;
         mTotalSteps = totalSteps;
 
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
index 0b65966..6c45af2 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
@@ -24,11 +24,15 @@
  * [Icon.Resource] to a resource.
  */
 sealed class Icon {
+    abstract val contentDescription: ContentDescription?
+
     data class Loaded(
         val drawable: Drawable,
+        override val contentDescription: ContentDescription?,
     ) : Icon()
 
     data class Resource(
         @DrawableRes val res: Int,
+        override val contentDescription: ContentDescription?,
     ) : Icon()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
new file mode 100644
index 0000000..5d0e08f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.common.shared.model
+
+import android.annotation.StringRes
+
+/**
+ * Models a text, that can either be already [loaded][Text.Loaded] or be a [reference]
+ * [Text.Resource] to a resource.
+ */
+sealed class Text {
+    data class Loaded(
+        val text: String?,
+    ) : Text()
+
+    data class Resource(
+        @StringRes val res: Int,
+    ) : Text()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
index d6433aa..93ae637 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
@@ -21,14 +21,16 @@
 
 object ContentDescriptionViewBinder {
     fun bind(
-        contentDescription: ContentDescription,
+        contentDescription: ContentDescription?,
         view: View,
     ) {
-        when (contentDescription) {
-            is ContentDescription.Loaded -> view.contentDescription = contentDescription.description
-            is ContentDescription.Resource -> {
-                view.contentDescription = view.context.resources.getString(contentDescription.res)
+        view.contentDescription =
+            when (contentDescription) {
+                null -> null
+                is ContentDescription.Loaded -> contentDescription.description
+                is ContentDescription.Resource -> {
+                    view.context.resources.getString(contentDescription.res)
+                }
             }
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
index aecee2a..108e22b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
@@ -24,6 +24,7 @@
         icon: Icon,
         view: ImageView,
     ) {
+        ContentDescriptionViewBinder.bind(icon.contentDescription, view)
         when (icon) {
             is Icon.Loaded -> view.setImageDrawable(icon.drawable)
             is Icon.Resource -> view.setImageResource(icon.res)
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
new file mode 100644
index 0000000..396e8bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.common.ui.binder
+
+import android.widget.TextView
+import com.android.systemui.common.shared.model.Text
+
+object TextViewBinder {
+    fun bind(view: TextView, viewModel: Text) {
+        view.text =
+            when (viewModel) {
+                is Text.Resource -> view.context.getString(viewModel.res)
+                is Text.Loaded -> viewModel.text
+            }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/drawable/CircularDrawable.kt b/packages/SystemUI/src/com/android/systemui/common/ui/drawable/CircularDrawable.kt
new file mode 100644
index 0000000..ec71c38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/drawable/CircularDrawable.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.common.ui.drawable
+
+import android.graphics.Canvas
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.DrawableWrapper
+import kotlin.math.min
+
+/** Renders the wrapped [Drawable] as a circle. */
+class CircularDrawable(
+    drawable: Drawable,
+) : DrawableWrapper(drawable) {
+    private val path: Path by lazy { Path() }
+
+    override fun onBoundsChange(bounds: Rect) {
+        super.onBoundsChange(bounds)
+        updateClipPath()
+    }
+
+    override fun draw(canvas: Canvas) {
+        canvas.save()
+        canvas.clipPath(path)
+        drawable?.draw(canvas)
+        canvas.restore()
+    }
+
+    private fun updateClipPath() {
+        path.reset()
+        path.addCircle(
+            bounds.centerX().toFloat(),
+            bounds.centerY().toFloat(),
+            min(bounds.width(), bounds.height()) / 2f,
+            Path.Direction.CW
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
index 91e75f6..822f8f2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
@@ -33,6 +33,12 @@
     fun hide()
 
     /**
+     * Returns the preferred activity to start, depending on if the user has favorited any
+     * controls.
+     */
+    fun resolveActivity(): Class<*>
+
+    /**
      * Request all open dialogs be closed. Set [immediately] to true to dismiss without
      * animations.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index c1e99f5..bf7d716 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -149,6 +149,19 @@
         }
     }
 
+    override fun resolveActivity(): Class<*> {
+        val allStructures = controlsController.get().getFavorites()
+        val selectedStructure = getPreferredStructure(allStructures)
+
+        return if (controlsController.get().addSeedingFavoritesCallback(onSeedingComplete)) {
+            ControlsActivity::class.java
+        } else if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) {
+            ControlsProviderSelectorActivity::class.java
+        } else {
+            ControlsActivity::class.java
+        }
+    }
+
     override fun show(
         parent: ViewGroup,
         onDismiss: Runnable,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index e1cbdcd..92eeace 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -18,7 +18,6 @@
 
 import android.app.Service;
 
-import com.android.systemui.ImageWallpaper;
 import com.android.systemui.SystemUIService;
 import com.android.systemui.doze.DozeService;
 import com.android.systemui.dreams.DreamOverlayService;
@@ -26,6 +25,7 @@
 import com.android.systemui.keyguard.KeyguardService;
 import com.android.systemui.screenrecord.RecordingService;
 import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
+import com.android.systemui.wallpapers.ImageWallpaper;
 
 import dagger.Binds;
 import dagger.Module;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java
index be156157..6b9d41c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java
@@ -19,7 +19,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.shared.system.WindowManagerWrapper;
 
 import dagger.Module;
 import dagger.Provides;
@@ -49,10 +48,4 @@
         return TaskStackChangeListeners.getInstance();
     }
 
-    /** */
-    @Provides
-    public WindowManagerWrapper providesWindowManagerWrapper() {
-        return WindowManagerWrapper.getInstance();
-    }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index d89c0be..b598554 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -101,6 +101,11 @@
          * Called when the always on suppression state changes. See {@link #isAlwaysOnSuppressed()}.
          */
         default void onAlwaysOnSuppressedChanged(boolean suppressed) {}
+
+        /**
+         * Called when the dozing state may have been updated.
+         */
+        default void onDozingChanged(boolean isDozing) {}
     }
 
     interface PulseCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index 823255c..f244cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -61,6 +61,7 @@
 
     private final Map<Integer, View> mStatusIcons = new HashMap<>();
     private ViewGroup mSystemStatusViewGroup;
+    private ViewGroup mExtraSystemStatusViewGroup;
 
     public DreamOverlayStatusBarView(Context context) {
         this(context, null);
@@ -98,7 +99,8 @@
         mStatusIcons.put(STATUS_ICON_PRIORITY_MODE_ON,
                 fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
 
-        mSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
+        mSystemStatusViewGroup = findViewById(R.id.dream_overlay_system_status);
+        mExtraSystemStatusViewGroup = findViewById(R.id.dream_overlay_extra_items);
     }
 
     void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
@@ -110,11 +112,12 @@
             icon.setContentDescription(contentDescription);
         }
         icon.setVisibility(show ? View.VISIBLE : View.GONE);
+        mSystemStatusViewGroup.setVisibility(areAnyStatusIconsVisible() ? View.VISIBLE : View.GONE);
     }
 
     void setExtraStatusBarItemViews(List<View> views) {
-        removeAllStatusBarItemViews();
-        views.forEach(view -> mSystemStatusViewGroup.addView(view));
+        removeAllExtraStatusBarItemViews();
+        views.forEach(view -> mExtraSystemStatusViewGroup.addView(view));
     }
 
     private View fetchStatusIconForResId(int resId) {
@@ -122,7 +125,16 @@
         return Objects.requireNonNull(statusIcon);
     }
 
-    void removeAllStatusBarItemViews() {
-        mSystemStatusViewGroup.removeAllViews();
+    void removeAllExtraStatusBarItemViews() {
+        mExtraSystemStatusViewGroup.removeAllViews();
+    }
+
+    private boolean areAnyStatusIconsVisible() {
+        for (int i = 0; i < mSystemStatusViewGroup.getChildCount(); i++) {
+            if (mSystemStatusViewGroup.getChildAt(i).getVisibility() == View.VISIBLE) {
+                return true;
+            }
+        }
+        return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 6f50550..aa59cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -192,7 +192,7 @@
         mDreamOverlayNotificationCountProvider.ifPresent(
                 provider -> provider.removeCallback(mNotificationCountCallback));
         mStatusBarItemsProvider.removeCallback(mStatusBarItemsProviderCallback);
-        mView.removeAllStatusBarItemViews();
+        mView.removeAllExtraStatusBarItemViews();
         mTouchInsetSession.clear();
 
         mIsAttached = false;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index c4553c4..2540035 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -66,6 +66,10 @@
     public static final UnreleasedFlag FSI_REQUIRES_KEYGUARD =
             new UnreleasedFlag(110, true);
 
+    public static final UnreleasedFlag INSTANT_VOICE_REPLY = new UnreleasedFlag(111, true);
+
+    // next id: 112
+
     /***************************************/
     // 200 - keyguard/lockscreen
 
@@ -88,19 +92,13 @@
     public static final ResourceBooleanFlag FACE_SCANNING_ANIM =
             new ResourceBooleanFlag(205, R.bool.config_enableFaceScanningAnimation);
 
-    /**
-     * Whether the KeyguardBottomArea(View|Controller) should use the modern architecture or the old
-     * one.
-     */
-    public static final ReleasedFlag MODERN_BOTTOM_AREA = new ReleasedFlag(206, true);
-
     public static final UnreleasedFlag LOCKSCREEN_CUSTOM_CLOCKS = new UnreleasedFlag(207);
   
     /**
      * Flag to enable the usage of the new bouncer data source. This is a refactor of and
      * eventual replacement of KeyguardBouncer.java.
      */
-    public static final ReleasedFlag MODERN_BOUNCER = new ReleasedFlag(208);
+    public static final UnreleasedFlag MODERN_BOUNCER = new UnreleasedFlag(208);
 
     /** Whether UserSwitcherActivity should use modern architecture. */
     public static final UnreleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
@@ -186,6 +184,12 @@
     // 801 - region sampling
     public static final UnreleasedFlag REGION_SAMPLING = new UnreleasedFlag(801);
 
+    // 802 - wallpaper rendering
+    public static final UnreleasedFlag USE_CANVAS_RENDERER = new UnreleasedFlag(802);
+
+    // 803 - screen contents translation
+    public static final UnreleasedFlag SCREEN_CONTENTS_TRANSLATION = new UnreleasedFlag(803);
+
     /***************************************/
     // 900 - media
     public static final ReleasedFlag MEDIA_TAP_TO_TRANSFER = new ReleasedFlag(900);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 898959e..1c6cec2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -29,6 +29,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
@@ -160,6 +161,9 @@
             return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
                     : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
         } else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+            boolean isOccludeByDream = apps.length > 0 && apps[0].taskInfo.topActivityType
+                    == WindowConfiguration.ACTIVITY_TYPE_DREAM;
+            if (isOccludeByDream) return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
             return TRANSIT_OLD_KEYGUARD_OCCLUDE;
         } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
             return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
@@ -169,7 +173,8 @@
         }
     }
 
-    // Wrap Keyguard going away animation
+    // Wrap Keyguard going away animation.
+    // Note: Also used for wrapping occlude by Dream animation. It works (with some redundancy).
     private static IRemoteTransition wrap(IRemoteAnimationRunner runner) {
         return new IRemoteTransition.Stub() {
             final ArrayMap<IBinder, IRemoteTransitionFinishedCallback> mFinishCallbacks =
@@ -271,6 +276,12 @@
             definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
                     occludeAnimationAdapter);
 
+            final RemoteAnimationAdapter occludeByDreamAnimationAdapter =
+                    new RemoteAnimationAdapter(
+                            mKeyguardViewMediator.getOccludeByDreamAnimationRunner(), 0, 0);
+            definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM,
+                    occludeByDreamAnimationAdapter);
+
             final RemoteAnimationAdapter unoccludeAnimationAdapter =
                     new RemoteAnimationAdapter(
                             mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0);
@@ -343,6 +354,27 @@
         f = new TransitionFilter();
         f.mTypeSet = new int[]{TRANSIT_KEYGUARD_UNOCCLUDE};
         mShellTransitions.registerRemote(f, unoccludeTransition);
+
+        Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_OCCLUDE for DREAM");
+        // Register for occluding by Dream
+        f = new TransitionFilter();
+        f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+        f.mRequirements = new TransitionFilter.Requirement[]{
+                new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+        // First require at-least one app of type DREAM showing that occludes.
+        f.mRequirements[0].mActivityType = WindowConfiguration.ACTIVITY_TYPE_DREAM;
+        f.mRequirements[0].mMustBeIndependent = false;
+        f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+        f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+        // Then require that we aren't closing any occludes (because this would mean a
+        // regular task->task or activity->activity animation not involving keyguard).
+        f.mRequirements[1].mNot = true;
+        f.mRequirements[1].mMustBeIndependent = false;
+        f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
+        f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+        mShellTransitions.registerRemote(f, new RemoteTransition(
+                wrap(mKeyguardViewMediator.getOccludeByDreamAnimationRunner()),
+                getIApplicationThread()));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 9ecfb75..c135b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -241,9 +241,8 @@
      */
     @VisibleForTesting
     var surfaceTransactionApplier: SyncRtSurfaceTransactionApplier? = null
-    private var surfaceBehindRemoteAnimationTarget: RemoteAnimationTarget? = null
+    private var surfaceBehindRemoteAnimationTargets: Array<RemoteAnimationTarget>? = null
     private var surfaceBehindRemoteAnimationStartTime: Long = 0
-    private var surfaceBehindParams: SyncRtSurfaceTransactionApplier.SurfaceParams? = null
 
     /**
      * Alpha value applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
@@ -282,7 +281,8 @@
      * window like any other app. This can be true while [willUnlockWithSmartspaceTransition] is
      * false, if the smartspace is not available or was not ready in time.
      */
-    private var willUnlockWithInWindowLauncherAnimations: Boolean = false
+    @VisibleForTesting
+    var willUnlockWithInWindowLauncherAnimations: Boolean = false
 
     /**
      * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
@@ -457,7 +457,7 @@
      * (fingerprint, tap, etc.) and the keyguard is going away.
      */
     fun notifyStartSurfaceBehindRemoteAnimation(
-        target: RemoteAnimationTarget,
+        targets: Array<RemoteAnimationTarget>,
         startTime: Long,
         requestedShowSurfaceBehindKeyguard: Boolean
     ) {
@@ -466,10 +466,7 @@
                     keyguardViewController.viewRootImpl.view)
         }
 
-        // New animation, new params.
-        surfaceBehindParams = null
-
-        surfaceBehindRemoteAnimationTarget = target
+        surfaceBehindRemoteAnimationTargets = targets
         surfaceBehindRemoteAnimationStartTime = startTime
 
         // If we specifically requested that the surface behind be made visible (vs. it being made
@@ -574,7 +571,7 @@
 
         // Now that the Launcher surface (with its smartspace positioned identically to ours) is
         // visible, hide our smartspace.
-        lockscreenSmartspace!!.visibility = View.INVISIBLE
+        lockscreenSmartspace?.visibility = View.INVISIBLE
 
         // As soon as the shade has animated out of the way, finish the keyguard exit animation. The
         // in-window animations in the Launcher window will end on their own.
@@ -596,7 +593,7 @@
      * keyguard dismiss amount and the method of dismissal.
      */
     private fun updateSurfaceBehindAppearAmount() {
-        if (surfaceBehindRemoteAnimationTarget == null) {
+        if (surfaceBehindRemoteAnimationTargets == null) {
             return
         }
 
@@ -709,63 +706,60 @@
      * cancelled).
      */
     fun setSurfaceBehindAppearAmount(amount: Float) {
-        if (surfaceBehindRemoteAnimationTarget == null) {
-            return
-        }
+        surfaceBehindRemoteAnimationTargets?.forEach { surfaceBehindRemoteAnimationTarget ->
+            val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget.screenSpaceBounds.height()
 
-        // Otherwise, animate in the surface's scale/transltion.
-        val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height()
+            var scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
+                    (1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
+                    MathUtils.clamp(amount, 0f, 1f))
 
-        var scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
-                (1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
-                MathUtils.clamp(amount, 0f, 1f))
-
-        // If we're dismissing via swipe to the Launcher, we'll play in-window scale animations, so
-        // don't also scale the window.
-        if (keyguardStateController.isDismissingFromSwipe &&
-                willUnlockWithInWindowLauncherAnimations) {
-            scaleFactor = 1f
-        }
-
-        // Scale up from a point at the center-bottom of the surface.
-        surfaceBehindMatrix.setScale(
-            scaleFactor,
-            scaleFactor,
-            surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f,
-            surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y
-        )
-
-        // Translate up from the bottom.
-        surfaceBehindMatrix.postTranslate(
-            0f,
-            surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
-        )
-
-        // If we're snapping the keyguard back, immediately begin fading it out.
-        val animationAlpha =
-            if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
-            else surfaceBehindAlpha
-
-        // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is unable
-        // to draw
-        val sc: SurfaceControl? = surfaceBehindRemoteAnimationTarget?.leash
-        if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE &&
-            sc?.isValid == true) {
-            with(SurfaceControl.Transaction()) {
-                setMatrix(sc, surfaceBehindMatrix, tmpFloat)
-                setCornerRadius(sc, roundedCornerRadius)
-                setAlpha(sc, animationAlpha)
-                apply()
+            // If we're dismissing via swipe to the Launcher, we'll play in-window scale animations,
+            // so don't also scale the window.
+            if (keyguardStateController.isDismissingFromSwipe &&
+                    willUnlockWithInWindowLauncherAnimations) {
+                scaleFactor = 1f
             }
-        } else {
-            applyParamsToSurface(
-                SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
-                    surfaceBehindRemoteAnimationTarget!!.leash)
-                    .withMatrix(surfaceBehindMatrix)
-                    .withCornerRadius(roundedCornerRadius)
-                    .withAlpha(animationAlpha)
-                    .build()
+
+            // Translate up from the bottom.
+            surfaceBehindMatrix.setTranslate(
+                    surfaceBehindRemoteAnimationTarget.screenSpaceBounds.left.toFloat(),
+                    surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
             )
+
+            // Scale up from a point at the center-bottom of the surface.
+            surfaceBehindMatrix.postScale(
+                    scaleFactor,
+                    scaleFactor,
+                    keyguardViewController.viewRootImpl.width / 2f,
+                    surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y
+            )
+
+            // If we're snapping the keyguard back, immediately begin fading it out.
+            val animationAlpha =
+                    if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
+                    else surfaceBehindAlpha
+
+            // SyncRtSurfaceTransactionApplier cannot apply transaction when the target view is
+            // unable to draw
+            val sc: SurfaceControl? = surfaceBehindRemoteAnimationTarget.leash
+            if (keyguardViewController.viewRootImpl.view?.visibility != View.VISIBLE &&
+                    sc?.isValid == true) {
+                with(SurfaceControl.Transaction()) {
+                    setMatrix(sc, surfaceBehindMatrix, tmpFloat)
+                    setCornerRadius(sc, roundedCornerRadius)
+                    setAlpha(sc, animationAlpha)
+                    apply()
+                }
+            } else {
+                applyParamsToSurface(
+                        SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
+                                surfaceBehindRemoteAnimationTarget.leash)
+                                .withMatrix(surfaceBehindMatrix)
+                                .withCornerRadius(roundedCornerRadius)
+                                .withAlpha(animationAlpha)
+                                .build()
+                )
+            }
         }
     }
 
@@ -790,8 +784,7 @@
         launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
 
         // That target is no longer valid since the animation finished, null it out.
-        surfaceBehindRemoteAnimationTarget = null
-        surfaceBehindParams = null
+        surfaceBehindRemoteAnimationTargets = null
 
         playingCannedUnlockAnimation = false
         willUnlockWithInWindowLauncherAnimations = false
@@ -823,7 +816,6 @@
 
     private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
         surfaceTransactionApplier!!.scheduleApply(params)
-        surfaceBehindParams = params
     }
 
     private fun fadeInSurfaceBehind() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2c60d5d..26db3ee4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -831,7 +831,7 @@
                 public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {}
 
                 @Override
-                public void onLaunchAnimationCancelled() {
+                public void onLaunchAnimationCancelled(@Nullable Boolean newKeyguardOccludedState) {
                     Log.d(TAG, "Occlude launch animation cancelled. Occluded state is now: "
                             + mOccluded);
                 }
@@ -887,6 +887,86 @@
     private IRemoteAnimationRunner mOccludeAnimationRunner =
             new OccludeActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
 
+    private final IRemoteAnimationRunner mOccludeByDreamAnimationRunner =
+            new IRemoteAnimationRunner.Stub() {
+                @Nullable private ValueAnimator mOccludeByDreamAnimator;
+
+                @Override
+                public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                    if (mOccludeByDreamAnimator != null) {
+                        mOccludeByDreamAnimator.cancel();
+                    }
+                    setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
+                    if (DEBUG) {
+                        Log.d(TAG, "Occlude by Dream animation cancelled. Occluded state is now: "
+                                + mOccluded);
+                    }
+                }
+
+                @Override
+                public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+                        RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+                        IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+                    setOccluded(true /* isOccluded */, true /* animate */);
+
+                    if (apps == null || apps.length == 0 || apps[0] == null) {
+                        if (DEBUG) {
+                            Log.d(TAG, "No apps provided to the OccludeByDream runner; "
+                                    + "skipping occluding animation.");
+                        }
+                        finishedCallback.onAnimationFinished();
+                        return;
+                    }
+
+                    final RemoteAnimationTarget primary = apps[0];
+                    final boolean isDream = (apps[0].taskInfo.topActivityType
+                            == WindowConfiguration.ACTIVITY_TYPE_DREAM);
+                    if (!isDream) {
+                        Log.w(TAG, "The occluding app isn't Dream; "
+                                + "finishing up. Please check that the config is correct.");
+                        finishedCallback.onAnimationFinished();
+                        return;
+                    }
+
+                    final SyncRtSurfaceTransactionApplier applier =
+                            new SyncRtSurfaceTransactionApplier(
+                                    mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+
+                    mContext.getMainExecutor().execute(() -> {
+                        if (mOccludeByDreamAnimator != null) {
+                            mOccludeByDreamAnimator.cancel();
+                        }
+
+                        mOccludeByDreamAnimator = ValueAnimator.ofFloat(0f, 1f);
+                        // Use the same duration as for the UNOCCLUDE.
+                        mOccludeByDreamAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
+                        mOccludeByDreamAnimator.setInterpolator(Interpolators.LINEAR);
+                        mOccludeByDreamAnimator.addUpdateListener(
+                                animation -> {
+                                    SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
+                                            paramsBuilder =
+                                            new SyncRtSurfaceTransactionApplier.SurfaceParams
+                                                    .Builder(primary.leash)
+                                                    .withAlpha(animation.getAnimatedFraction());
+                                    applier.scheduleApply(paramsBuilder.build());
+                                });
+                        mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                try {
+                                    finishedCallback.onAnimationFinished();
+                                    mOccludeByDreamAnimator = null;
+                                } catch (RemoteException e) {
+                                    e.printStackTrace();
+                                }
+                            }
+                        });
+
+                        mOccludeByDreamAnimator.start();
+                    });
+                }
+            };
+
     /**
      * Animation controller for activities that unocclude the keyguard. This does not use the
      * ActivityLaunchAnimator since we're just translating down, rather than emerging from a view
@@ -1682,6 +1762,10 @@
         return mOccludeAnimationRunner;
     }
 
+    public IRemoteAnimationRunner getOccludeByDreamAnimationRunner() {
+        return mOccludeByDreamAnimationRunner;
+    }
+
     public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
         return mUnoccludeAnimationRunner;
     }
@@ -2496,18 +2580,10 @@
                 mInteractionJankMonitor.begin(
                         createInteractionJankMonitorConf("DismissPanel"));
 
-                // Apply the opening animation on root task if exists
-                RemoteAnimationTarget aniTarget = apps[0];
-                for (RemoteAnimationTarget tmpTarget : apps) {
-                    if (tmpTarget.taskId != -1 && !tmpTarget.hasAnimatingParent) {
-                        aniTarget = tmpTarget;
-                        break;
-                    }
-                }
                 // Pass the surface and metadata to the unlock animation controller.
                 mKeyguardUnlockAnimationControllerLazy.get()
                         .notifyStartSurfaceBehindRemoteAnimation(
-                                aniTarget, startTime, mSurfaceBehindRemoteAnimationRequested);
+                                apps, startTime, mSurfaceBehindRemoteAnimationRequested);
             } else {
                 mInteractionJankMonitor.begin(
                         createInteractionJankMonitorConf("RemoteAnimationDisabled"));
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index e52d9ee..840a4b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.Position
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.doze.DozeHost
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import javax.inject.Inject
@@ -28,6 +29,7 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 
 /** Defines interface for classes that encapsulate application state for the keyguard. */
 interface KeyguardRepository {
@@ -102,6 +104,7 @@
 constructor(
     statusBarStateController: StatusBarStateController,
     keyguardStateController: KeyguardStateController,
+    dozeHost: DozeHost,
 ) : KeyguardRepository {
     private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
     override val animateBottomAreaDozingTransitions =
@@ -136,19 +139,21 @@
         awaitClose { keyguardStateController.removeCallback(callback) }
     }
 
-    override val isDozing: Flow<Boolean> = conflatedCallbackFlow {
-        val callback =
-            object : StatusBarStateController.StateListener {
-                override fun onDozingChanged(isDozing: Boolean) {
-                    trySendWithFailureLogging(isDozing, TAG, "updated isDozing")
-                }
+    override val isDozing: Flow<Boolean> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : DozeHost.Callback {
+                        override fun onDozingChanged(isDozing: Boolean) {
+                            trySendWithFailureLogging(isDozing, TAG, "updated isDozing")
+                        }
+                    }
+                dozeHost.addCallback(callback)
+                trySendWithFailureLogging(false, TAG, "initial isDozing: false")
+
+                awaitClose { dozeHost.removeCallback(callback) }
             }
+            .distinctUntilChanged()
 
-        statusBarStateController.addCallback(callback)
-        trySendWithFailureLogging(statusBarStateController.isDozing, TAG, "initial isDozing")
-
-        awaitClose { statusBarStateController.removeCallback(callback) }
-    }
     override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
         val callback =
             object : StatusBarStateController.StateListener {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 9a69e26..95acc0b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -32,6 +32,7 @@
 import kotlin.reflect.KClass
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onStart
 
 @SysUISingleton
 class KeyguardQuickAffordanceInteractor
@@ -88,7 +89,15 @@
         position: KeyguardQuickAffordancePosition
     ): Flow<KeyguardQuickAffordanceModel> {
         val configs = registry.getAll(position)
-        return combine(configs.map { config -> config.state }) { states ->
+        return combine(
+            configs.map { config ->
+                // We emit an initial "Hidden" value to make sure that there's always an initial
+                // value and avoid subtle bugs where the downstream isn't receiving any values
+                // because one config implementation is not emitting an initial value. For example,
+                // see b/244296596.
+                config.state.onStart { emit(KeyguardQuickAffordanceConfig.State.Hidden) }
+            }
+        ) { states ->
             val index = states.indexOfFirst { it is KeyguardQuickAffordanceConfig.State.Visible }
             if (index != -1) {
                 val visibleState = states[index] as KeyguardQuickAffordanceConfig.State.Visible
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 8f32ff9..ac2c9b1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -94,6 +94,7 @@
                                 hasFavorites = favorites?.isNotEmpty() == true,
                                 hasServiceInfos = serviceInfos.isNotEmpty(),
                                 iconResourceId = component.getTileImageId(),
+                                visibility = component.getVisibility(),
                             ),
                             TAG,
                         )
@@ -110,9 +111,16 @@
         isFeatureEnabled: Boolean,
         hasFavorites: Boolean,
         hasServiceInfos: Boolean,
+        visibility: ControlsComponent.Visibility,
         @DrawableRes iconResourceId: Int?,
     ): KeyguardQuickAffordanceConfig.State {
-        return if (isFeatureEnabled && hasFavorites && hasServiceInfos && iconResourceId != null) {
+        return if (
+            isFeatureEnabled &&
+                hasFavorites &&
+                hasServiceInfos &&
+                iconResourceId != null &&
+                visibility == ControlsComponent.Visibility.AVAILABLE
+        ) {
             KeyguardQuickAffordanceConfig.State.Visible(
                 icon = ContainedDrawable.WithResource(iconResourceId),
                 contentDescriptionResourceId = component.getTileTitleId(),
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java
new file mode 100644
index 0000000..7f1ad6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BiometricMessagesLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/**
+ * A {@link com.android.systemui.log.LogBuffer} for BiometricMessages processing such as
+ * {@link com.android.systemui.biometrics.FaceHelpMessageDeferral}
+ */
+@Qualifier
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BiometricMessagesLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index c2a8764..756feb0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -287,6 +287,17 @@
     }
 
     /**
+     * Provides a {@link LogBuffer} for use by
+     * {@link com.android.systemui.biometrics.FaceHelpMessageDeferral}.
+     */
+    @Provides
+    @SysUISingleton
+    @BiometricMessagesLog
+    public static LogBuffer provideBiometricMessagesLogBuffer(LogBufferFactory factory) {
+        return factory.create("BiometricMessagesLog", 150);
+    }
+
+    /**
      * Provides a {@link LogBuffer} for use by the status bar network controller.
      */
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 4c6aa7b..cc77ed1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -458,6 +458,7 @@
         val existingPlayer = MediaPlayerData.getMediaPlayer(key)
         val curVisibleMediaKey = MediaPlayerData.playerKeys()
                 .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+        val isCurVisibleMediaPlaying = MediaPlayerData.getMediaData(curVisibleMediaKey)?.isPlaying
         if (existingPlayer == null) {
             val newPlayer = mediaControlPanelFactory.get()
             newPlayer.attachPlayer(MediaViewHolder.create(
@@ -472,13 +473,23 @@
                 key, data, newPlayer, systemClock, isSsReactivated, debugLogger
             )
             updatePlayerToState(newPlayer, noAnimation = true)
-            reorderAllPlayers(curVisibleMediaKey)
+            if (data.active) {
+                reorderAllPlayers(curVisibleMediaKey)
+            } else {
+                needsReordering = true
+            }
         } else {
             existingPlayer.bindPlayer(data, key)
             MediaPlayerData.addMediaPlayer(
                 key, data, existingPlayer, systemClock, isSsReactivated, debugLogger
             )
-            if (isReorderingAllowed || shouldScrollToActivePlayer) {
+            // Check the playing status of both current visible and new media players
+            // To make sure we scroll to the active playing media card.
+            if (isReorderingAllowed ||
+                    shouldScrollToActivePlayer &&
+                    data.isPlaying == true &&
+                    isCurVisibleMediaPlaying == false
+            ) {
                 reorderAllPlayers(curVisibleMediaKey)
             } else {
                 needsReordering = true
@@ -1035,6 +1046,15 @@
         }
     }
 
+    fun getMediaData(mediaSortKey: MediaSortKey?): MediaData? {
+        mediaData.forEach { (key, value) ->
+            if (value == mediaSortKey) {
+                return mediaData[key]?.data
+            }
+        }
+        return null
+    }
+
     fun getMediaPlayer(key: String): MediaControlPanel? {
         return mediaData.get(key)?.let { mediaPlayers.get(it) }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index ae4c7c7..6baf6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dreams.DreamOverlayStateController
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.dream.MediaDreamComplication
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.NotifPanelEvents
 import com.android.systemui.statusbar.CrossFadeHelper
@@ -401,7 +402,7 @@
         }
 
     /**
-     * Is the doze animation currently Running
+     * Is the dream overlay currently active
      */
     private var dreamOverlayActive: Boolean = false
         private set(value) {
@@ -412,6 +413,17 @@
         }
 
     /**
+     * Is the dream media complication currently active
+     */
+    private var dreamMediaComplicationActive: Boolean = false
+        private set(value) {
+            if (field != value) {
+                field = value
+                updateDesiredLocation(forceNoAnimation = true)
+            }
+        }
+
+    /**
      * The current cross fade progress. 0.5f means it's just switching
      * between the start and the end location and the content is fully faded, while 0.75f means
      * that we're halfway faded in again in the target state.
@@ -500,6 +512,12 @@
         })
 
         dreamOverlayStateController.addCallback(object : DreamOverlayStateController.Callback {
+            override fun onComplicationsChanged() {
+                dreamMediaComplicationActive = dreamOverlayStateController.complications.any {
+                    it is MediaDreamComplication
+                }
+            }
+
             override fun onStateChanged() {
                 dreamOverlayStateController.isOverlayActive.also { dreamOverlayActive = it }
             }
@@ -1068,7 +1086,7 @@
         val onLockscreen = (!bypassController.bypassEnabled &&
             (statusbarState == StatusBarState.KEYGUARD))
         val location = when {
-            dreamOverlayActive -> LOCATION_DREAM_OVERLAY
+            dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
             (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
             qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
             !hasActiveMedia -> LOCATION_QS
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 75fa2f1..0b9b32b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -96,8 +96,9 @@
             mToken = token;
 
             mRingtone = new Ringtone(getContextForUser(user), false);
-            mRingtone.setAudioAttributes(aa);
+            mRingtone.setAudioAttributesField(aa);
             mRingtone.setUri(uri, volumeShaperConfig);
+            mRingtone.createLocalMediaPlayer();
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index b39770d..2d09ddd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -310,6 +310,7 @@
             if (icon.getType() != Icon.TYPE_BITMAP && icon.getType() != Icon.TYPE_ADAPTIVE_BITMAP) {
                 // icon doesn't support getBitmap, use default value for color scheme
                 updateButtonBackgroundColorFilter();
+                updateDialogBackgroundColor();
             } else {
                 Configuration config = mContext.getResources().getConfiguration();
                 int currentNightMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
@@ -319,11 +320,14 @@
                 if (colorSetUpdated) {
                     mAdapter.updateColorScheme(wallpaperColors, isDarkThemeOn);
                     updateButtonBackgroundColorFilter();
+                    updateDialogBackgroundColor();
                 }
             }
             mHeaderIcon.setVisibility(View.VISIBLE);
             mHeaderIcon.setImageIcon(icon);
         } else {
+            updateButtonBackgroundColorFilter();
+            updateDialogBackgroundColor();
             mHeaderIcon.setVisibility(View.GONE);
         }
         if (appSourceIcon != null) {
@@ -381,11 +385,16 @@
 
     private void updateButtonBackgroundColorFilter() {
         ColorFilter buttonColorFilter = new PorterDuffColorFilter(
-                mAdapter.getController().getColorButtonBackground(),
+                mMediaOutputController.getColorButtonBackground(),
                 PorterDuff.Mode.SRC_IN);
         mDoneButton.getBackground().setColorFilter(buttonColorFilter);
         mStopButton.getBackground().setColorFilter(buttonColorFilter);
-        mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
+        mDoneButton.setTextColor(mMediaOutputController.getColorPositiveButtonText());
+    }
+
+    private void updateDialogBackgroundColor() {
+        getDialogView().getBackground().setTint(mMediaOutputController.getColorDialogBackground());
+        mDeviceListLayout.setBackgroundColor(mMediaOutputController.getColorDialogBackground());
     }
 
     private Drawable resizeDrawable(Drawable drawable, int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 96817c9..f040e06 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -133,6 +133,7 @@
     @VisibleForTesting
     LocalMediaManager mLocalMediaManager;
     private MediaOutputMetricLogger mMetricLogger;
+    private int mCurrentState;
 
     private int mColorItemContent;
     private int mColorSeekbarProgress;
@@ -140,6 +141,7 @@
     private int mColorItemBackground;
     private int mColorConnectedItemBackground;
     private int mColorPositiveButtonText;
+    private int mColorDialogBackground;
     private float mInactiveRadius;
     private float mActiveRadius;
 
@@ -188,6 +190,8 @@
                 R.dimen.media_output_dialog_background_radius);
         mActiveRadius = mContext.getResources().getDimension(
                 R.dimen.media_output_dialog_active_background_radius);
+        mColorDialogBackground = Utils.getColorStateListDefaultColor(mContext,
+                R.color.media_dialog_background);
     }
 
     void start(@NonNull Callback cb) {
@@ -204,6 +208,9 @@
                 if (TextUtils.equals(controller.getPackageName(), mPackageName)) {
                     mMediaController = controller;
                     mMediaController.unregisterCallback(mCb);
+                    if (mMediaController.getPlaybackState() != null) {
+                        mCurrentState = mMediaController.getPlaybackState().getState();
+                    }
                     mMediaController.registerCallback(mCb);
                     break;
                 }
@@ -461,6 +468,7 @@
             mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
             mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
             mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
+            mColorDialogBackground = mCurrentColorScheme.getNeutral1().get(10); // N1-900
         } else {
             mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
             mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
@@ -468,6 +476,7 @@
             mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
             mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
             mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
+            mColorDialogBackground = mCurrentColorScheme.getBackgroundColor();
         }
     }
 
@@ -487,6 +496,10 @@
         return mColorPositiveButtonText;
     }
 
+    public int getColorDialogBackground() {
+        return mColorDialogBackground;
+    }
+
     public int getColorItemContent() {
         return mColorItemContent;
     }
@@ -976,10 +989,16 @@
 
         @Override
         public void onPlaybackStateChanged(PlaybackState playbackState) {
-            final int state = playbackState.getState();
-            if (state == PlaybackState.STATE_STOPPED || state == PlaybackState.STATE_PAUSED) {
+            final int newState =
+                    playbackState == null ? PlaybackState.STATE_STOPPED : playbackState.getState();
+            if (mCurrentState == newState) {
+                return;
+            }
+
+            if (newState == PlaybackState.STATE_STOPPED || newState == PlaybackState.STATE_PAUSED) {
                 mCallback.onMediaStoppedOrPaused();
             }
+            mCurrentState = newState;
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
index 6fe06e0..7d3e82c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
@@ -107,7 +107,8 @@
         SysUiStatsLog.write(
                 SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__ADJUST_VOLUME,
-                getInteractionDeviceType(source));
+                getInteractionDeviceType(source),
+                getLoggingPackageName());
     }
 
     /**
@@ -121,7 +122,8 @@
         SysUiStatsLog.write(
                 SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__STOP_CASTING,
-                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE);
+                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE,
+                getLoggingPackageName());
     }
 
     /**
@@ -135,7 +137,8 @@
         SysUiStatsLog.write(
                 SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
                 SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__EXPANSION,
-                getInteractionDeviceType(source));
+                getInteractionDeviceType(source),
+                getLoggingPackageName());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
index acd04f2..dc1488e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
@@ -19,6 +19,7 @@
 import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
 
 import android.content.Context;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -38,6 +39,9 @@
  * the media complication as appropriate
  */
 public class MediaDreamSentinel extends CoreStartable {
+    private static final String TAG = "MediaDreamSentinel";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     private final MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
         private boolean mAdded;
         @Override
@@ -46,11 +50,17 @@
 
         @Override
         public void onMediaDataRemoved(@NonNull String key) {
+            final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia();
+            if (DEBUG) {
+                Log.d(TAG, "onMediaDataRemoved(" + key + "), mAdded=" + mAdded + ", hasActiveMedia="
+                        + hasActiveMedia);
+            }
+
             if (!mAdded) {
                 return;
             }
 
-            if (mMediaDataManager.hasActiveMedia()) {
+            if (hasActiveMedia) {
                 return;
             }
 
@@ -71,11 +81,24 @@
                 return;
             }
 
+            final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia();
+            if (DEBUG) {
+                Log.d(TAG, "onMediaDataLoaded(" + key + "), mAdded=" + mAdded + ", hasActiveMedia="
+                        + hasActiveMedia);
+            }
+
+            // Media data can become inactive without triggering onMediaDataRemoved.
+            if (mAdded && !hasActiveMedia) {
+                mAdded = false;
+                mDreamOverlayStateController.removeComplication(mMediaEntryComplication);
+                return;
+            }
+
             if (mAdded) {
                 return;
             }
 
-            if (!mMediaDataManager.hasActiveMedia()) {
+            if (!hasActiveMedia) {
                 return;
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
deleted file mode 100644
index 3a0ac1b..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.taptotransfer.common
-
-import android.annotation.LayoutRes
-import android.annotation.SuppressLint
-import android.content.Context
-import android.content.pm.PackageManager
-import android.graphics.PixelFormat
-import android.graphics.drawable.Drawable
-import android.os.PowerManager
-import android.os.SystemClock
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import android.view.WindowManager
-import android.view.accessibility.AccessibilityManager
-import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS
-import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS
-import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT
-import androidx.annotation.CallSuper
-import com.android.internal.widget.CachingIconView
-import com.android.settingslib.Utils
-import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
-
-/**
- * A superclass controller that provides common functionality for showing chips on the sender device
- * and the receiver device.
- *
- * Subclasses need to override and implement [updateChipView], which is where they can control what
- * gets displayed to the user.
- *
- * The generic type T is expected to contain all the information necessary for the subclasses to
- * display the chip in a certain state, since they receive <T> in [updateChipView].
- */
-abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
-        internal val context: Context,
-        internal val logger: MediaTttLogger,
-        internal val windowManager: WindowManager,
-        private val viewUtil: ViewUtil,
-        @Main private val mainExecutor: DelayableExecutor,
-        private val accessibilityManager: AccessibilityManager,
-        private val configurationController: ConfigurationController,
-        private val powerManager: PowerManager,
-        @LayoutRes private val chipLayoutRes: Int,
-) {
-    /**
-     * Window layout params that will be used as a starting point for the [windowLayoutParams] of
-     * all subclasses.
-     */
-    @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
-    internal val commonWindowLayoutParams = WindowManager.LayoutParams().apply {
-        width = WindowManager.LayoutParams.WRAP_CONTENT
-        height = WindowManager.LayoutParams.WRAP_CONTENT
-        type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
-        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-        title = WINDOW_TITLE
-        format = PixelFormat.TRANSLUCENT
-        setTrustedOverlay()
-    }
-
-    /**
-     * The window layout parameters we'll use when attaching the view to a window.
-     *
-     * Subclasses must override this to provide their specific layout params, and they should use
-     * [commonWindowLayoutParams] as part of their layout params.
-     */
-    internal abstract val windowLayoutParams: WindowManager.LayoutParams
-
-    /** The chip view currently being displayed. Null if the chip is not being displayed. */
-    private var chipView: ViewGroup? = null
-
-    /** The chip info currently being displayed. Null if the chip is not being displayed. */
-    internal var chipInfo: T? = null
-
-    /** A [Runnable] that, when run, will cancel the pending timeout of the chip. */
-    private var cancelChipViewTimeout: Runnable? = null
-
-    /**
-     * Displays the chip with the provided [newChipInfo].
-     *
-     * This method handles inflating and attaching the view, then delegates to [updateChipView] to
-     * display the correct information in the chip.
-     */
-    fun displayChip(newChipInfo: T) {
-        val currentChipView = chipView
-
-        if (currentChipView != null) {
-            updateChipView(newChipInfo, currentChipView)
-        } else {
-            // The chip is new, so set up all our callbacks and inflate the view
-            configurationController.addCallback(displayScaleListener)
-            // Wake the screen if necessary so the user will see the chip. (Per b/239426653, we want
-            // the chip to show over the dream state, so we should only wake up if the screen is
-            // completely off.)
-            if (!powerManager.isScreenOn) {
-                powerManager.wakeUp(
-                        SystemClock.uptimeMillis(),
-                        PowerManager.WAKE_REASON_APPLICATION,
-                        "com.android.systemui:media_tap_to_transfer_activated"
-                )
-            }
-
-            inflateAndUpdateChip(newChipInfo)
-        }
-
-        // Cancel and re-set the chip timeout each time we get a new state.
-        val timeout = accessibilityManager.getRecommendedTimeoutMillis(
-            newChipInfo.getTimeoutMs().toInt(),
-            // Not all chips have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
-            // include it just to be safe.
-            FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
-       )
-        cancelChipViewTimeout?.run()
-        cancelChipViewTimeout = mainExecutor.executeDelayed(
-            { removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
-            timeout.toLong()
-        )
-    }
-
-    /** Inflates a new chip view, updates it with [newChipInfo], and adds the view to the window. */
-    private fun inflateAndUpdateChip(newChipInfo: T) {
-        val newChipView = LayoutInflater
-                .from(context)
-                .inflate(chipLayoutRes, null) as ViewGroup
-        chipView = newChipView
-        updateChipView(newChipInfo, newChipView)
-        windowManager.addView(newChipView, windowLayoutParams)
-        animateChipIn(newChipView)
-    }
-
-    /** Removes then re-inflates the chip. */
-    private fun reinflateChip() {
-        val currentChipInfo = chipInfo
-        if (chipView == null || currentChipInfo == null) { return }
-
-        windowManager.removeView(chipView)
-        inflateAndUpdateChip(currentChipInfo)
-    }
-
-    private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
-        override fun onDensityOrFontScaleChanged() {
-            reinflateChip()
-        }
-    }
-
-    /**
-     * Hides the chip.
-     *
-     * @param removalReason a short string describing why the chip was removed (timeout, state
-     *     change, etc.)
-     */
-    open fun removeChip(removalReason: String) {
-        if (chipView == null) { return }
-        logger.logChipRemoval(removalReason)
-        configurationController.removeCallback(displayScaleListener)
-        windowManager.removeView(chipView)
-        chipView = null
-        chipInfo = null
-        // No need to time the chip out since it's already gone
-        cancelChipViewTimeout?.run()
-    }
-
-    /**
-     * A method implemented by subclasses to update [currentChipView] based on [newChipInfo].
-     */
-    @CallSuper
-    open fun updateChipView(newChipInfo: T, currentChipView: ViewGroup) {
-        chipInfo = newChipInfo
-    }
-
-    /**
-     * A method that can be implemented by subclcasses to do custom animations for when the chip
-     * appears.
-     */
-    open fun animateChipIn(chipView: ViewGroup) {}
-
-    /**
-     * Returns the size that the icon should be, or null if no size override is needed.
-     */
-    open fun getIconSize(isAppIcon: Boolean): Int? = null
-
-    /**
-     * An internal method to set the icon on the view.
-     *
-     * This is in the common superclass since both the sender and the receiver show an icon.
-     *
-     * @param appPackageName the package name of the app playing the media. Will be used to fetch
-     *   the app icon and app name if overrides aren't provided.
-     *
-     * @return the content description of the icon.
-     */
-    internal fun setIcon(
-        currentChipView: ViewGroup,
-        appPackageName: String?,
-        appIconDrawableOverride: Drawable? = null,
-        appNameOverride: CharSequence? = null,
-    ): CharSequence {
-        val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
-        val iconInfo = getIconInfo(appPackageName)
-
-        getIconSize(iconInfo.isAppIcon)?.let { size ->
-            val lp = appIconView.layoutParams
-            lp.width = size
-            lp.height = size
-            appIconView.layoutParams = lp
-        }
-
-        appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
-        appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
-        return appIconView.contentDescription
-    }
-
-    /**
-     * Returns the information needed to display the icon.
-     *
-     * The information will either contain app name and icon of the app playing media, or a default
-     * name and icon if we can't find the app name/icon.
-     */
-    private fun getIconInfo(appPackageName: String?): IconInfo {
-        if (appPackageName != null) {
-            try {
-                return IconInfo(
-                    iconName = context.packageManager.getApplicationInfo(
-                        appPackageName, PackageManager.ApplicationInfoFlags.of(0)
-                    ).loadLabel(context.packageManager).toString(),
-                    icon = context.packageManager.getApplicationIcon(appPackageName),
-                    isAppIcon = true
-                )
-            } catch (e: PackageManager.NameNotFoundException) {
-                Log.w(TAG, "Cannot find package $appPackageName", e)
-            }
-        }
-        return IconInfo(
-            iconName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
-            icon = context.resources.getDrawable(R.drawable.ic_cast).apply {
-                this.setTint(
-                    Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
-                )
-            },
-            isAppIcon = false
-        )
-    }
-}
-
-// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
-// UpdateMediaTapToTransferReceiverDisplayTest
-private const val WINDOW_TITLE = "Media Transfer Chip View"
-private val TAG = MediaTttChipControllerCommon::class.simpleName!!
-
-object MediaTttRemovalReason {
-    const val REASON_TIMEOUT = "TIMEOUT"
-    const val REASON_SCREEN_TAP = "SCREEN_TAP"
-}
-
-private data class IconInfo(
-    val iconName: String,
-    val icon: Drawable,
-    /** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
-    val isAppIcon: Boolean
-)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
index aa10f7e..b565f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
@@ -18,38 +18,57 @@
 
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogLevel
+import com.android.systemui.temporarydisplay.TemporaryViewLogger
 
 /**
  * A logger for media tap-to-transfer events.
  *
- * @property deviceTypeTag the type of device triggering the logs -- "Sender" or "Receiver".
+ * @param deviceTypeTag the type of device triggering the logs -- "Sender" or "Receiver".
  */
 class MediaTttLogger(
-    private val deviceTypeTag: String,
-    private val buffer: LogBuffer
-){
+    deviceTypeTag: String,
+    buffer: LogBuffer
+) : TemporaryViewLogger(buffer, BASE_TAG + deviceTypeTag) {
     /** Logs a change in the chip state for the given [mediaRouteId]. */
-    fun logStateChange(stateName: String, mediaRouteId: String) {
+    fun logStateChange(stateName: String, mediaRouteId: String, packageName: String?) {
         buffer.log(
-            BASE_TAG + deviceTypeTag,
+            tag,
             LogLevel.DEBUG,
             {
                 str1 = stateName
                 str2 = mediaRouteId
+                str3 = packageName
             },
-            { "State changed to $str1 for ID=$str2" }
+            { "State changed to $str1 for ID=$str2 package=$str3" }
         )
     }
 
-    /** Logs that we removed the chip for the given [reason]. */
-    fun logChipRemoval(reason: String) {
+    /** Logs that we couldn't find information for [packageName]. */
+    fun logPackageNotFound(packageName: String) {
         buffer.log(
-            BASE_TAG + deviceTypeTag,
+            tag,
             LogLevel.DEBUG,
-            { str1 = reason },
-            { "Chip removed due to $str1" }
+            { str1 = packageName },
+            { "Package $str1 could not be found" }
         )
     }
+
+    /**
+     * Logs that a removal request has been bypassed (ignored).
+     *
+     * @param removalReason the reason that the chip removal was requested.
+     * @param bypassReason the reason that the request was bypassed.
+     */
+    fun logRemovalBypass(removalReason: String, bypassReason: String) {
+        buffer.log(
+            tag,
+            LogLevel.DEBUG,
+            {
+                str1 = removalReason
+                str2 = bypassReason
+            },
+            { "Chip removal requested due to $str1; however, removal was ignored because $str2" })
+    }
 }
 
 private const val BASE_TAG = "MediaTtt"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
new file mode 100644
index 0000000..792ae7c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.common
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.graphics.drawable.Drawable
+import com.android.internal.widget.CachingIconView
+import com.android.settingslib.Utils
+import com.android.systemui.R
+
+/** Utility methods for media tap-to-transfer. */
+class MediaTttUtils {
+    companion object {
+        // Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
+        // UpdateMediaTapToTransferReceiverDisplayTest
+        const val WINDOW_TITLE = "Media Transfer Chip View"
+        const val WAKE_REASON = "MEDIA_TRANSFER_ACTIVATED"
+
+        /**
+         * Returns the information needed to display the icon.
+         *
+         * The information will either contain app name and icon of the app playing media, or a
+         * default name and icon if we can't find the app name/icon.
+         *
+         * @param appPackageName the package name of the app playing the media.
+         * @param logger the logger to use for any errors.
+         */
+        fun getIconInfoFromPackageName(
+            context: Context,
+            appPackageName: String?,
+            logger: MediaTttLogger
+        ): IconInfo {
+            if (appPackageName != null) {
+                try {
+                    val contentDescription =
+                        context.packageManager
+                            .getApplicationInfo(
+                                appPackageName,
+                                PackageManager.ApplicationInfoFlags.of(0)
+                            )
+                            .loadLabel(context.packageManager)
+                            .toString()
+                    return IconInfo(
+                        contentDescription,
+                        drawable = context.packageManager.getApplicationIcon(appPackageName),
+                        isAppIcon = true
+                    )
+                } catch (e: PackageManager.NameNotFoundException) {
+                    logger.logPackageNotFound(appPackageName)
+                }
+            }
+            return IconInfo(
+                contentDescription =
+                    context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+                drawable =
+                    context.resources.getDrawable(R.drawable.ic_cast).apply {
+                        this.setTint(
+                            Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+                        )
+                    },
+                isAppIcon = false
+            )
+        }
+
+        /**
+         * Sets an icon to be displayed by the given view.
+         *
+         * @param iconSize the size in pixels that the icon should be. If null, the size of
+         * [appIconView] will not be adjusted.
+         */
+        fun setIcon(
+            appIconView: CachingIconView,
+            icon: Drawable,
+            iconContentDescription: CharSequence,
+            iconSize: Int? = null,
+        ) {
+            iconSize?.let { size ->
+                val lp = appIconView.layoutParams
+                lp.width = size
+                lp.height = size
+                appIconView.layoutParams = lp
+            }
+
+            appIconView.contentDescription = iconContentDescription
+            appIconView.setImageDrawable(icon)
+        }
+    }
+}
+
+data class IconInfo(
+    val contentDescription: String,
+    val drawable: Drawable,
+    /**
+     * True if [drawable] is the app's icon, and false if [drawable] is some generic default icon.
+     */
+    val isAppIcon: Boolean
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 35a6c74..dfd9e22 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -34,15 +34,15 @@
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
 import com.android.systemui.media.taptotransfer.common.MediaTttLogger
+import com.android.systemui.media.taptotransfer.common.MediaTttUtils
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
 import com.android.systemui.util.animation.AnimationUtil.Companion.frames
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
 import javax.inject.Inject
 
 /**
@@ -56,23 +56,23 @@
         context: Context,
         @MediaTttReceiverLogger logger: MediaTttLogger,
         windowManager: WindowManager,
-        viewUtil: ViewUtil,
         mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
         @Main private val mainHandler: Handler,
         private val uiEventLogger: MediaTttReceiverUiEventLogger,
-) : MediaTttChipControllerCommon<ChipReceiverInfo>(
+) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
         powerManager,
         R.layout.media_ttt_chip_receiver,
+        MediaTttUtils.WINDOW_TITLE,
+        MediaTttUtils.WAKE_REASON,
 ) {
     @SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
     override val windowLayoutParams = commonWindowLayoutParams.apply {
@@ -110,7 +110,7 @@
     ) {
         val chipState: ChipStateReceiver? = ChipStateReceiver.getReceiverStateFromId(displayState)
         val stateName = chipState?.name ?: "Invalid"
-        logger.logStateChange(stateName, routeInfo.id)
+        logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName)
 
         if (chipState == null) {
             Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
@@ -119,18 +119,18 @@
         uiEventLogger.logReceiverStateChange(chipState)
 
         if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
-            removeChip(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
+            removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
             return
         }
         if (appIcon == null) {
-            displayChip(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
+            displayView(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
             return
         }
 
         appIcon.loadDrawableAsync(
                 context,
                 Icon.OnDrawableLoadedListener { drawable ->
-                    displayChip(ChipReceiverInfo(routeInfo, drawable, appName))
+                    displayView(ChipReceiverInfo(routeInfo, drawable, appName))
                 },
                 // Notify the listener on the main handler since the listener will update
                 // the UI.
@@ -138,19 +138,32 @@
         )
     }
 
-    override fun updateChipView(newChipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
-        super.updateChipView(newChipInfo, currentChipView)
-        val iconName = setIcon(
-                currentChipView,
-                newChipInfo.routeInfo.clientPackageName,
-                newChipInfo.appIconDrawableOverride,
-                newChipInfo.appNameOverride
+    override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
+        super.updateView(newInfo, currentView)
+
+        val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
+            context, newInfo.routeInfo.clientPackageName, logger
         )
-        currentChipView.contentDescription = iconName
+        val iconDrawable = newInfo.appIconDrawableOverride ?: iconInfo.drawable
+        val iconContentDescription = newInfo.appNameOverride ?: iconInfo.contentDescription
+        val iconSize = context.resources.getDimensionPixelSize(
+            if (iconInfo.isAppIcon) {
+                R.dimen.media_ttt_icon_size_receiver
+            } else {
+                R.dimen.media_ttt_generic_icon_size_receiver
+            }
+        )
+
+        MediaTttUtils.setIcon(
+            currentView.requireViewById(R.id.app_icon),
+            iconDrawable,
+            iconContentDescription,
+            iconSize,
+        )
     }
 
-    override fun animateChipIn(chipView: ViewGroup) {
-        val appIconView = chipView.requireViewById<View>(R.id.app_icon)
+    override fun animateViewIn(view: ViewGroup) {
+        val appIconView = view.requireViewById<View>(R.id.app_icon)
         appIconView.animate()
                 .translationYBy(-1 * getTranslationAmount().toFloat())
                 .setDuration(30.frames)
@@ -160,19 +173,10 @@
                 .setDuration(5.frames)
                 .start()
         // Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
-        appIconView.postOnAnimation { chipView.requestAccessibilityFocus() }
-        startRipple(chipView.requireViewById(R.id.ripple))
+        appIconView.postOnAnimation { view.requestAccessibilityFocus() }
+        startRipple(view.requireViewById(R.id.ripple))
     }
 
-    override fun getIconSize(isAppIcon: Boolean): Int? =
-        context.resources.getDimensionPixelSize(
-            if (isAppIcon) {
-                R.dimen.media_ttt_icon_size_receiver
-            } else {
-                R.dimen.media_ttt_generic_icon_size_receiver
-            }
-        )
-
     /** Returns the amount that the chip will be translated by in its intro animation. */
     private fun getTranslationAmount(): Int {
         return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation)
@@ -216,7 +220,7 @@
     val routeInfo: MediaRoute2Info,
     val appIconDrawableOverride: Drawable?,
     val appNameOverride: CharSequence?
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
     override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index a153cb6..4379d25 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -25,7 +25,7 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.statusbar.IUndoMediaTransferCallback
 import com.android.systemui.R
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
 
 /**
  * A class enumerating all the possible states of the media tap-to-transfer chip on the sender
@@ -34,8 +34,7 @@
  * @property stateInt the integer from [StatusBarManager] corresponding with this state.
  * @property stringResId the res ID of the string that should be displayed in the chip. Null if the
  *   state should not have the chip be displayed.
- * @property isMidTransfer true if the state represents that a transfer is currently ongoing.
- * @property isTransferFailure true if the state represents that the transfer has failed.
+ * @property transferStatus the transfer status that the chip state represents.
  * @property timeout the amount of time this chip should display on the screen before it times out
  *   and disappears.
  */
@@ -43,8 +42,7 @@
     @StatusBarManager.MediaTransferSenderState val stateInt: Int,
     val uiEvent: UiEventLogger.UiEventEnum,
     @StringRes val stringResId: Int?,
-    val isMidTransfer: Boolean = false,
-    val isTransferFailure: Boolean = false,
+    val transferStatus: TransferStatus,
     val timeout: Long = DEFAULT_TIMEOUT_MILLIS
 ) {
     /**
@@ -56,6 +54,7 @@
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST,
         R.string.media_move_closer_to_start_cast,
+        transferStatus = TransferStatus.NOT_STARTED,
     ),
 
     /**
@@ -68,6 +67,7 @@
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST,
         R.string.media_move_closer_to_end_cast,
+        transferStatus = TransferStatus.NOT_STARTED,
     ),
 
     /**
@@ -78,7 +78,7 @@
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED,
         R.string.media_transfer_playing_different_device,
-        isMidTransfer = true,
+        transferStatus = TransferStatus.IN_PROGRESS,
         timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
     ),
 
@@ -90,7 +90,7 @@
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
         R.string.media_transfer_playing_this_device,
-        isMidTransfer = true,
+        transferStatus = TransferStatus.IN_PROGRESS,
         timeout = TRANSFER_TRIGGERED_TIMEOUT_MILLIS
     ),
 
@@ -100,7 +100,8 @@
     TRANSFER_TO_RECEIVER_SUCCEEDED(
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED,
-        R.string.media_transfer_playing_different_device
+        R.string.media_transfer_playing_different_device,
+        transferStatus = TransferStatus.SUCCEEDED,
     ) {
         override fun undoClickListener(
             controllerSender: MediaTttChipControllerSender,
@@ -120,7 +121,7 @@
                 // state, but that may take too long to go through the binder and the user may be
                 // confused ast o why the UI hasn't changed yet. So, we immediately change the UI
                 // here.
-                controllerSender.displayChip(
+                controllerSender.displayView(
                     ChipSenderInfo(
                         TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback
                     )
@@ -135,7 +136,8 @@
     TRANSFER_TO_THIS_DEVICE_SUCCEEDED(
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
-        R.string.media_transfer_playing_this_device
+        R.string.media_transfer_playing_this_device,
+        transferStatus = TransferStatus.SUCCEEDED,
     ) {
         override fun undoClickListener(
             controllerSender: MediaTttChipControllerSender,
@@ -155,7 +157,7 @@
                 // state, but that may take too long to go through the binder and the user may be
                 // confused as to why the UI hasn't changed yet. So, we immediately change the UI
                 // here.
-                controllerSender.displayChip(
+                controllerSender.displayView(
                     ChipSenderInfo(
                         TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback
                     )
@@ -169,7 +171,7 @@
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED,
         R.string.media_transfer_failed,
-        isTransferFailure = true
+        transferStatus = TransferStatus.FAILED,
     ),
 
     /** A state representing that a transfer back to this device has failed. */
@@ -177,14 +179,15 @@
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED,
         R.string.media_transfer_failed,
-        isTransferFailure = true
+        transferStatus = TransferStatus.FAILED,
     ),
 
     /** A state representing that this device is far away from any receiver device. */
     FAR_FROM_RECEIVER(
         StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
         MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER,
-        stringResId = null
+        stringResId = null,
+        transferStatus = TransferStatus.TOO_FAR,
     );
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index 9335489..e539f3f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -33,14 +33,14 @@
 import com.android.systemui.animation.ViewHierarchyAnimator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
 import com.android.systemui.media.taptotransfer.common.MediaTttLogger
-import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
+import com.android.systemui.media.taptotransfer.common.MediaTttUtils
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
 import javax.inject.Inject
 
 /**
@@ -53,22 +53,22 @@
         context: Context,
         @MediaTttSenderLogger logger: MediaTttLogger,
         windowManager: WindowManager,
-        viewUtil: ViewUtil,
         @Main mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
         private val uiEventLogger: MediaTttSenderUiEventLogger
-) : MediaTttChipControllerCommon<ChipSenderInfo>(
+) : TemporaryViewDisplayController<ChipSenderInfo, MediaTttLogger>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
         powerManager,
         R.layout.media_ttt_chip,
+        MediaTttUtils.WINDOW_TITLE,
+        MediaTttUtils.WAKE_REASON,
 ) {
     override val windowLayoutParams = commonWindowLayoutParams.apply {
         gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
@@ -97,7 +97,7 @@
     ) {
         val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState)
         val stateName = chipState?.name ?: "Invalid"
-        logger.logStateChange(stateName, routeInfo.id)
+        logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName)
 
         if (chipState == null) {
             Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
@@ -106,53 +106,59 @@
         uiEventLogger.logSenderStateChange(chipState)
 
         if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
-            removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
+            removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER.name)
         } else {
-            displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback))
+            displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
         }
     }
 
-    /** Displays the chip view for the given state. */
-    override fun updateChipView(
-            newChipInfo: ChipSenderInfo,
-            currentChipView: ViewGroup
+    override fun updateView(
+        newInfo: ChipSenderInfo,
+        currentView: ViewGroup
     ) {
-        super.updateChipView(newChipInfo, currentChipView)
+        super.updateView(newInfo, currentView)
 
-        val chipState = newChipInfo.state
+        val chipState = newInfo.state
 
         // App icon
-        val iconName = setIcon(currentChipView, newChipInfo.routeInfo.clientPackageName)
+        val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
+            context, newInfo.routeInfo.clientPackageName, logger
+        )
+        MediaTttUtils.setIcon(
+            currentView.requireViewById(R.id.app_icon),
+            iconInfo.drawable,
+            iconInfo.contentDescription
+        )
 
         // Text
-        val otherDeviceName = newChipInfo.routeInfo.name.toString()
+        val otherDeviceName = newInfo.routeInfo.name.toString()
         val chipText = chipState.getChipTextString(context, otherDeviceName)
-        currentChipView.requireViewById<TextView>(R.id.text).text = chipText
+        currentView.requireViewById<TextView>(R.id.text).text = chipText
 
         // Loading
-        currentChipView.requireViewById<View>(R.id.loading).visibility =
-            chipState.isMidTransfer.visibleIfTrue()
+        currentView.requireViewById<View>(R.id.loading).visibility =
+            (chipState.transferStatus == TransferStatus.IN_PROGRESS).visibleIfTrue()
 
         // Undo
-        val undoView = currentChipView.requireViewById<View>(R.id.undo)
+        val undoView = currentView.requireViewById<View>(R.id.undo)
         val undoClickListener = chipState.undoClickListener(
-                this, newChipInfo.routeInfo, newChipInfo.undoCallback, uiEventLogger
+                this, newInfo.routeInfo, newInfo.undoCallback, uiEventLogger
         )
         undoView.setOnClickListener(undoClickListener)
         undoView.visibility = (undoClickListener != null).visibleIfTrue()
 
         // Failure
-        currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
-            chipState.isTransferFailure.visibleIfTrue()
+        currentView.requireViewById<View>(R.id.failure_icon).visibility =
+            (chipState.transferStatus == TransferStatus.FAILED).visibleIfTrue()
 
         // For accessibility
-        currentChipView.requireViewById<ViewGroup>(
+        currentView.requireViewById<ViewGroup>(
                 R.id.media_ttt_sender_chip_inner
-        ).contentDescription = "$iconName $chipText"
+        ).contentDescription = "${iconInfo.contentDescription} $chipText"
     }
 
-    override fun animateChipIn(chipView: ViewGroup) {
-        val chipInnerView = chipView.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
+    override fun animateViewIn(view: ViewGroup) {
+        val chipInnerView = view.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
         ViewHierarchyAnimator.animateAddition(
             chipInnerView,
             ViewHierarchyAnimator.Hotspot.TOP,
@@ -165,14 +171,21 @@
         )
     }
 
-    override fun removeChip(removalReason: String) {
-        // Don't remove the chip if we're mid-transfer since the user should still be able to
-        // see the status of the transfer. (But do remove it if it's finally timed out.)
-        if (chipInfo?.state?.isMidTransfer == true &&
-                removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
+    override fun removeView(removalReason: String) {
+        // Don't remove the chip if we're in progress or succeeded, since the user should still be
+        // able to see the status of the transfer. (But do remove it if it's finally timed out.)
+        val transferStatus = info?.state?.transferStatus
+        if (
+            (transferStatus == TransferStatus.IN_PROGRESS ||
+                transferStatus == TransferStatus.SUCCEEDED) &&
+            removalReason != TemporaryDisplayRemovalReason.REASON_TIMEOUT
+        ) {
+            logger.logRemovalBypass(
+                removalReason, bypassReason = "transferStatus=${transferStatus.name}"
+            )
             return
         }
-        super.removeChip(removalReason)
+        super.removeView(removalReason)
     }
 
     private fun Boolean.visibleIfTrue(): Int {
@@ -188,7 +201,7 @@
     val state: ChipStateSender,
     val routeInfo: MediaRoute2Info,
     val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
     override fun getTimeoutMs() = state.timeout
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/TransferStatus.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/TransferStatus.kt
new file mode 100644
index 0000000..f15720d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/TransferStatus.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.sender
+
+/** Represents the different possible transfer states that we could be in. */
+enum class TransferStatus {
+    /** The transfer hasn't started yet. */
+    NOT_STARTED,
+    /** The transfer is currently ongoing but hasn't completed yet. */
+    IN_PROGRESS,
+    /** The transfer has completed successfully. */
+    SUCCEEDED,
+    /** The transfer has completed with a failure. */
+    FAILED,
+    /** The device is too far away to do a transfer. */
+    TOO_FAR,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 75e48d2..30947e8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -35,7 +35,6 @@
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
 import static com.android.systemui.navigationbar.NavBarHelper.transitionMode;
 import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
@@ -229,10 +228,7 @@
     private Locale mLocale;
     private int mLayoutDirection;
 
-    private boolean mAllowForceNavBarHandleOpaque;
-    private boolean mForceNavBarHandleOpaque;
     private Optional<Long> mHomeButtonLongPressDurationMs;
-    private boolean mIsCurrentUserSetup;
 
     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
@@ -379,37 +375,6 @@
         }
 
         @Override
-        public void onNavBarButtonAlphaChanged(float alpha, boolean animate) {
-            if (!mIsCurrentUserSetup) {
-                // If the current user is not yet setup, then don't update any button alphas
-                return;
-            }
-            if (QuickStepContract.isLegacyMode(mNavBarMode)) {
-                // Don't allow the bar buttons to be affected by the alpha
-                return;
-            }
-
-            ButtonDispatcher buttonDispatcher = null;
-            boolean forceVisible = false;
-            if (QuickStepContract.isGesturalMode(mNavBarMode)) {
-                // Disallow home handle animations when in gestural
-                animate = false;
-                forceVisible = mAllowForceNavBarHandleOpaque && mForceNavBarHandleOpaque;
-                buttonDispatcher = mView.getHomeHandle();
-                if (getBarTransitions() != null) {
-                    getBarTransitions().setBackgroundOverrideAlpha(alpha);
-                }
-            } else if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
-                buttonDispatcher = mView.getBackButton();
-            }
-            if (buttonDispatcher != null) {
-                buttonDispatcher.setVisibility(
-                        (forceVisible || alpha > 0) ? View.VISIBLE : View.INVISIBLE);
-                buttonDispatcher.setAlpha(forceVisible ? 1f : alpha, animate);
-            }
-        }
-
-        @Override
         public void onHomeRotationEnabled(boolean enabled) {
             mView.getRotationButtonController().setHomeRotationEnabled(enabled);
         }
@@ -456,15 +421,10 @@
             new DeviceConfig.OnPropertiesChangedListener() {
                 @Override
                 public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                    if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
-                        mForceNavBarHandleOpaque = properties.getBoolean(
-                                NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
-                    }
-
                     if (properties.getKeyset().contains(HOME_BUTTON_LONG_PRESS_DURATION_MS)) {
                         mHomeButtonLongPressDurationMs = Optional.of(
-                            properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0)
-                        ).filter(duration -> duration != 0);
+                            properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0))
+                                .filter(duration -> duration != 0);
                         if (mView != null) {
                             reconfigureHomeLongClick();
                         }
@@ -472,14 +432,6 @@
                 }
             };
 
-    private final DeviceProvisionedController.DeviceProvisionedListener mUserSetupListener =
-            new DeviceProvisionedController.DeviceProvisionedListener() {
-                @Override
-                public void onUserSetupChanged() {
-                    mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
-                }
-            };
-
     private final NotificationShadeDepthController.DepthListener mDepthListener =
             new NotificationShadeDepthController.DepthListener() {
                 boolean mHasBlurs;
@@ -660,12 +612,6 @@
         mCommandQueue.addCallback(this);
         mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
         mNavBarHelper.init();
-        mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
-                R.bool.allow_force_nav_bar_handle_opaque);
-        mForceNavBarHandleOpaque = mDeviceConfigProxy.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                NAV_BAR_HANDLE_FORCE_OPAQUE,
-                /* defaultValue = */ true);
         mHomeButtonLongPressDurationMs = Optional.of(mDeviceConfigProxy.getLong(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 HOME_BUTTON_LONG_PRESS_DURATION_MS,
@@ -685,8 +631,6 @@
         // Respect the latest disabled-flags.
         mCommandQueue.recomputeDisableFlags(mDisplayId, false);
 
-        mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
-        mDeviceProvisionedController.addCallback(mUserSetupListener);
         mNotificationShadeDepthController.addListener(mDepthListener);
     }
 
@@ -698,7 +642,6 @@
 
         mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         mNavBarHelper.destroy();
-        mDeviceProvisionedController.removeCallback(mUserSetupListener);
         mNotificationShadeDepthController.removeListener(mDepthListener);
 
         mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 9e1ba5f..9702488 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -39,6 +39,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -51,6 +52,7 @@
 import android.view.WindowInsets;
 import android.view.WindowInsetsController.Behavior;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.widget.FrameLayout;
@@ -78,7 +80,6 @@
 import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
@@ -775,13 +776,24 @@
         updateSlippery();
         reloadNavIcons();
         updateNavButtonIcons();
-        mBgExecutor.execute(() -> WindowManagerWrapper.getInstance()
-                .setNavBarVirtualKeyHapticFeedbackEnabled(!mShowSwipeUpUi));
+        mBgExecutor.execute(() -> setNavBarVirtualKeyHapticFeedbackEnabled(!mShowSwipeUpUi));
         getHomeButton().setAccessibilityDelegate(
                 mShowSwipeUpUi ? mQuickStepAccessibilityDelegate : null);
     }
 
     /**
+     * Enable or disable haptic feedback on the navigation bar buttons.
+     */
+    private void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                    .setNavBarVirtualKeyHapticFeedbackEnabled(enabled);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to enable or disable navigation bar button haptics: ", e);
+        }
+    }
+
+    /**
      * Updates the {@link WindowManager.LayoutParams.FLAG_SLIPPERY} state dependent on if swipe up
      * is enabled, or the notifications is fully opened without being in an animated state. If
      * slippery is enabled, touch events will leave the nav bar window and enter into the fullscreen
diff --git a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
index 3709a86..7184fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/power/dagger/PowerModule.java
@@ -20,13 +20,18 @@
 import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.power.PowerNotificationWarnings;
 import com.android.systemui.power.PowerUI;
+import com.android.systemui.power.data.repository.PowerRepositoryModule;
 
 import dagger.Binds;
 import dagger.Module;
 
 
 /** Dagger Module for code in the power package. */
-@Module
+@Module(
+        includes = {
+                PowerRepositoryModule.class,
+        }
+)
 public interface PowerModule {
     /** */
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
new file mode 100644
index 0000000..b2e04bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.power.data.repository
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.PowerManager
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Defines interface for classes that act as source of truth for power-related data. */
+interface PowerRepository {
+    /** Whether the device is interactive. Starts with the current state. */
+    val isInteractive: Flow<Boolean>
+}
+
+@SysUISingleton
+class PowerRepositoryImpl
+@Inject
+constructor(
+    manager: PowerManager,
+    dispatcher: BroadcastDispatcher,
+) : PowerRepository {
+
+    override val isInteractive: Flow<Boolean> = conflatedCallbackFlow {
+        fun send() {
+            trySendWithFailureLogging(manager.isInteractive, TAG)
+        }
+
+        val receiver =
+            object : BroadcastReceiver() {
+                override fun onReceive(context: Context?, intent: Intent?) {
+                    send()
+                }
+            }
+
+        dispatcher.registerReceiver(
+            receiver,
+            IntentFilter().apply {
+                addAction(Intent.ACTION_SCREEN_ON)
+                addAction(Intent.ACTION_SCREEN_OFF)
+            },
+        )
+        send()
+
+        awaitClose { dispatcher.unregisterReceiver(receiver) }
+    }
+
+    companion object {
+        private const val TAG = "PowerRepository"
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
similarity index 61%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
rename to packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
index 1de740a..491da65 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,17 +12,15 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.power.data.repository
 
-import android.annotation.UserIdInt;
-import android.content.Context;
+import dagger.Binds
+import dagger.Module
 
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
+@Module
+interface PowerRepositoryModule {
+    @Binds fun bindRepository(impl: PowerRepositoryImpl): PowerRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
new file mode 100644
index 0000000..3f799f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.power.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.power.data.repository.PowerRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Hosts business logic for interacting with the power system. */
+@SysUISingleton
+class PowerInteractor
+@Inject
+constructor(
+    repository: PowerRepository,
+) {
+    /** Whether the screen is on or off. */
+    val isInteractive: Flow<Boolean> = repository.isInteractive
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 56298fa..e1289a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -16,6 +16,7 @@
 
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -30,15 +31,11 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.PagedTileLayout.PageListener;
-import com.android.systemui.qs.QSHost.Callback;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.qs.tileimpl.HeightOverrideable;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -47,16 +44,26 @@
 
 import javax.inject.Inject;
 
-/** */
+/**
+ * Performs the animated transition between the QQS and QS views.
+ *
+ * <p>The transition is driven externally via {@link #setPosition(float)}, where 0 is a fully
+ * collapsed QQS and one a fully expanded QS.
+ *
+ * <p>This implementation maintains a set of {@code TouchAnimator} to transition the properties of
+ * views both in QQS and QS. These {@code TouchAnimator} are re-created lazily if contents of either
+ * view change, see {@link #requestAnimatorUpdate()}.
+ *
+ * <p>During the transition, both QS and QQS are visible. For overlapping tiles (Whenever the QS
+ * shows the first page), the corresponding QS tiles are hidden until QS is fully expanded.
+ */
 @QSScope
-public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener,
-        OnAttachStateChangeListener, Tunable {
+public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener,
+        TouchAnimator.Listener, OnLayoutChangeListener,
+        OnAttachStateChangeListener {
 
     private static final String TAG = "QSAnimator";
 
-    private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
-    private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
-
     private static final float EXPANDED_TILE_DELAY = .86f;
     //Non first page delays
     private static final float QS_TILE_LABEL_FADE_OUT_START = 0.15f;
@@ -65,7 +72,6 @@
 
     public static final float SHORT_PARALLAX_AMOUNT = 0.1f;
 
-
     /**
      * List of all views that will be reset when clearing animation state
      * see {@link #clearAnimationState()} }
@@ -93,7 +99,7 @@
     // slider, as well as animating the alpha of the QS tile layout (as we are tracking QQS tiles)
     @Nullable
     private TouchAnimator mFirstPageAnimator;
-    // TranslationX animator for QQS/QS tiles
+    // TranslationX animator for QQS/QS tiles. Only used on the first page!
     private TouchAnimator mTranslationXAnimator;
     // TranslationY animator for QS tiles (and their components) in the first page
     private TouchAnimator mTranslationYAnimator;
@@ -101,13 +107,14 @@
     private TouchAnimator mQQSTranslationYAnimator;
     // Animates alpha of permanent views (QS tile layout, QQS tiles) when not in first page
     private TouchAnimator mNonfirstPageAlphaAnimator;
-    // TranslatesY the QS Tile layout using QS.getHeightDiff()
-    private TouchAnimator mQSTileLayoutTranslatorAnimator;
     // This animates fading of media player
     private TouchAnimator mAllPagesDelayedAnimator;
-    // Animator for brightness slider(s)
+    // Brightness slider translation driver, uses mQSExpansionPathInterpolator.yInterpolator
     @Nullable
-    private TouchAnimator mBrightnessAnimator;
+    private TouchAnimator mBrightnessTranslationAnimator;
+    // Brightness slider opacity driver. Uses linear interpolator.
+    @Nullable
+    private TouchAnimator mBrightnessOpacityAnimator;
     // Animator for Footer actions in QQS
     private TouchAnimator mQQSFooterActionsAnimator;
     // Height animator for QQS tiles (height changing from QQS size to QS size)
@@ -125,16 +132,12 @@
     private boolean mNeedsAnimatorUpdate = false;
     private boolean mOnKeyguard;
 
-    private boolean mAllowFancy;
-    private boolean mFullRows;
     private int mNumQuickTiles;
     private int mLastQQSTileHeight;
     private float mLastPosition;
     private final QSTileHost mHost;
     private final Executor mExecutor;
-    private final TunerService mTunerService;
     private boolean mShowCollapsedOnKeyguard;
-    private boolean mTranslateWhileExpanding;
     private int mQQSTop;
 
     private int[] mTmpLoc1 = new int[2];
@@ -153,7 +156,6 @@
         mQuickStatusBarHeader = quickStatusBarHeader;
         mHost = qsTileHost;
         mExecutor = executor;
-        mTunerService = tunerService;
         mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
         mHost.addCallback(this);
         mQsPanelController.addOnAttachStateChangeListener(this);
@@ -199,7 +201,6 @@
         setCurrentPosition();
     }
 
-
     private void setCurrentPosition() {
         setPosition(mLastPosition);
     }
@@ -210,30 +211,15 @@
     }
 
     @Override
-    public void onViewAttachedToWindow(@Nullable View v) {
-        mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
-                MOVE_FULL_ROWS);
-    }
-
-    @Override
-    public void onViewDetachedFromWindow(View v) {
-        mHost.removeCallback(this);
-        mTunerService.removeTunable(this);
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (ALLOW_FANCY_ANIMATION.equals(key)) {
-            mAllowFancy = TunerService.parseIntegerSwitch(newValue, true);
-            if (!mAllowFancy) {
-                clearAnimationState();
-            }
-        } else if (MOVE_FULL_ROWS.equals(key)) {
-            mFullRows = TunerService.parseIntegerSwitch(newValue, true);
-        }
+    public void onViewAttachedToWindow(@NonNull View view) {
         updateAnimators();
     }
 
+    @Override
+    public void onViewDetachedFromWindow(@NonNull View v) {
+        mHost.removeCallback(this);
+    }
+
     private void addNonFirstPageAnimators(int page) {
         Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
         if (pair != null) {
@@ -312,13 +298,6 @@
 
         QSTileLayout tileLayout = mQsPanelController.getTileLayout();
         mAllViews.add((View) tileLayout);
-        int heightDiff = mQs.getHeightDiff();
-        if (!mTranslateWhileExpanding) {
-            heightDiff *= SHORT_PARALLAX_AMOUNT;
-        }
-        mQSTileLayoutTranslatorAnimator = new Builder()
-                .addFloat(tileLayout, "translationY", heightDiff, 0)
-                .build();
 
         mLastQQSTileHeight = 0;
 
@@ -339,8 +318,7 @@
                 View view = mQs.getView();
 
                 // This case: less tiles to animate in small displays.
-                if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()
-                        && mAllowFancy) {
+                if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()) {
                     // Quick tiles.
                     QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
                     if (quickTileView == null) continue;
@@ -422,12 +400,7 @@
                     mAnimatedQsViews.add(tileView);
                     mAllViews.add(quickTileView);
                     mAllViews.add(quickTileView.getSecondaryLabel());
-                } else if (mFullRows && isIconInAnimatedRow(count)) {
-
-                    firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
-
-                    mAllViews.add(tileIcon);
-                } else {
+                } else if (!isIconInAnimatedRow(count)) {
                     // Pretend there's a corresponding QQS tile (for the position) that we are
                     // expanding from.
                     SideLabelTileLayout qqsLayout =
@@ -457,44 +430,42 @@
             }
         }
 
-        if (mAllowFancy) {
-            animateBrightnessSlider(firstPageBuilder);
+        animateBrightnessSlider();
 
-            mFirstPageAnimator = firstPageBuilder
-                    // Fade in the tiles/labels as we reach the final position.
-                    .addFloat(tileLayout, "alpha", 0, 1)
-                    .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
-                    .setListener(this)
-                    .build();
+        mFirstPageAnimator = firstPageBuilder
+                // Fade in the tiles/labels as we reach the final position.
+                .addFloat(tileLayout, "alpha", 0, 1)
+                .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
+                .setListener(this)
+                .build();
 
-            // Fade in the media player as we reach the final position
-            Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
-            if (mQsPanelController.shouldUseHorizontalLayout()
-                    && mQsPanelController.mMediaHost.hostView != null) {
-                builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
-            } else {
-                // In portrait, media view should always be visible
-                mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
-            }
-            mAllPagesDelayedAnimator = builder.build();
-            translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
-            qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
-            translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
-            if (mOnFirstPage) {
-                // Only recreate this animator if we're in the first page. That way we know that
-                // the first page is attached and has the proper positions/measures.
-                mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
-            }
-            mTranslationYAnimator = translationYBuilder.build();
-            mTranslationXAnimator = translationXBuilder.build();
-            if (mQQSTileHeightAnimator != null) {
-                mQQSTileHeightAnimator.setInterpolator(
-                        mQSExpansionPathInterpolator.getYInterpolator());
-            }
-            if (mOtherFirstPageTilesHeightAnimator != null) {
-                mOtherFirstPageTilesHeightAnimator.setInterpolator(
-                        mQSExpansionPathInterpolator.getYInterpolator());
-            }
+        // Fade in the media player as we reach the final position
+        Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
+        if (mQsPanelController.shouldUseHorizontalLayout()
+                && mQsPanelController.mMediaHost.hostView != null) {
+            builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
+        } else {
+            // In portrait, media view should always be visible
+            mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
+        }
+        mAllPagesDelayedAnimator = builder.build();
+        translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+        qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+        translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
+        if (mOnFirstPage) {
+            // Only recreate this animator if we're in the first page. That way we know that
+            // the first page is attached and has the proper positions/measures.
+            mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
+        }
+        mTranslationYAnimator = translationYBuilder.build();
+        mTranslationXAnimator = translationXBuilder.build();
+        if (mQQSTileHeightAnimator != null) {
+            mQQSTileHeightAnimator.setInterpolator(
+                    mQSExpansionPathInterpolator.getYInterpolator());
+        }
+        if (mOtherFirstPageTilesHeightAnimator != null) {
+            mOtherFirstPageTilesHeightAnimator.setInterpolator(
+                    mQSExpansionPathInterpolator.getYInterpolator());
         }
         mNonfirstPageAlphaAnimator = nonFirstPageAlphaBuilder
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -568,7 +539,7 @@
 
             if (animator == null) {
                 animator = new HeightExpansionAnimator(
-                                this, mLastQQSTileHeight, tileView.getMeasuredHeight());
+                        this, mLastQQSTileHeight, tileView.getMeasuredHeight());
                 animator.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
             }
             animator.addView(tileView);
@@ -585,7 +556,9 @@
         return new Pair<>(animator, builder.build());
     }
 
-    private void animateBrightnessSlider(Builder firstPageBuilder) {
+    private void animateBrightnessSlider() {
+        mBrightnessTranslationAnimator = null;
+        mBrightnessOpacityAnimator = null;
         View qsBrightness = mQsPanelController.getBrightnessView();
         View qqsBrightness = mQuickQSPanelController.getBrightnessView();
         if (qqsBrightness != null && qqsBrightness.getVisibility() == View.VISIBLE) {
@@ -593,25 +566,45 @@
             mAnimatedQsViews.add(qsBrightness);
             mAllViews.add(qqsBrightness);
             int translationY = getRelativeTranslationY(qsBrightness, qqsBrightness);
-            mBrightnessAnimator = new Builder()
+            mBrightnessTranslationAnimator = new Builder()
                     // we need to animate qs brightness even if animation will not be visible,
                     // as we might start from sliderScaleY set to 0.3 if device was in collapsed QS
                     // portrait orientation before
                     .addFloat(qsBrightness, "sliderScaleY", 0.3f, 1)
                     .addFloat(qqsBrightness, "translationY", 0, translationY)
+                    .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator())
                     .build();
         } else if (qsBrightness != null) {
-            firstPageBuilder.addFloat(qsBrightness, "translationY",
-                    qsBrightness.getMeasuredHeight() * 0.5f, 0);
-            mBrightnessAnimator = new Builder()
+            // The brightness slider's visible bottom edge must maintain a constant margin from the
+            // QS tiles during transition. Thus the slider must (1) perform the same vertical
+            // translation as the tiles, and (2) compensate for the slider scaling.
+
+            // For (1), compute the distance via the vertical distance between QQS and QS tile
+            // layout top.
+            View quickSettingsRootView = mQs.getView();
+            View qsTileLayout = (View) mQsPanelController.getTileLayout();
+            View qqsTileLayout = (View) mQuickQSPanelController.getTileLayout();
+            getRelativePosition(mTmpLoc1, qsTileLayout, quickSettingsRootView);
+            getRelativePosition(mTmpLoc2, qqsTileLayout, quickSettingsRootView);
+            int tileMovement = mTmpLoc2[1] - mTmpLoc1[1];
+
+            // For (2), the slider scales to the vertical center, so compensate with half the
+            // height at full collapse.
+            float scaleCompensation = qsBrightness.getMeasuredHeight() * 0.5f;
+            mBrightnessTranslationAnimator = new Builder()
+                    .addFloat(qsBrightness, "translationY", scaleCompensation + tileMovement, 0)
+                    .addFloat(qsBrightness, "sliderScaleY", 0, 1)
+                    .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator())
+                    .build();
+
+            // While the slider's position and unfurl is animated throughouth the motion, the
+            // fade in happens independently.
+            mBrightnessOpacityAnimator = new Builder()
                     .addFloat(qsBrightness, "alpha", 0, 1)
-                    .addFloat(qsBrightness, "sliderScaleY", 0.3f, 1)
-                    .setInterpolator(Interpolators.ALPHA_IN)
-                    .setStartDelay(0.3f)
+                    .setStartDelay(0.2f)
+                    .setEndDelay(1 - 0.5f)
                     .build();
             mAllViews.add(qsBrightness);
-        } else {
-            mBrightnessAnimator = null;
         }
     }
 
@@ -639,7 +632,7 @@
     }
 
     private void getRelativePositionInt(int[] loc1, View view, View parent) {
-        if(view == parent || view == null) return;
+        if (view == parent || view == null) return;
         // Ignore tile pages as they can have some offset we don't want to take into account in
         // RTL.
         if (!isAPage(view)) {
@@ -672,7 +665,6 @@
             }
         }
         mLastPosition = position;
-        if (!mAllowFancy) return;
         if (mOnFirstPage) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
@@ -694,11 +686,13 @@
         if (mQQSTileHeightAnimator != null) {
             mQQSTileHeightAnimator.setPosition(position);
         }
-        mQSTileLayoutTranslatorAnimator.setPosition(position);
         mQQSTranslationYAnimator.setPosition(position);
         mAllPagesDelayedAnimator.setPosition(position);
-        if (mBrightnessAnimator != null) {
-            mBrightnessAnimator.setPosition(position);
+        if (mBrightnessOpacityAnimator != null) {
+            mBrightnessOpacityAnimator.setPosition(position);
+        }
+        if (mBrightnessTranslationAnimator != null) {
+            mBrightnessTranslationAnimator.setPosition(position);
         }
         if (mQQSFooterActionsAnimator != null) {
             mQQSFooterActionsAnimator.setPosition(position);
@@ -792,13 +786,6 @@
         setCurrentPosition();
     };
 
-    /**
-     * True whe QS will be pulled from the top, false when it will be clipped.
-     */
-    public void setTranslateWhileExpanding(boolean shouldTranslate) {
-        mTranslateWhileExpanding = shouldTranslate;
-    }
-
     private static class HeightExpansionAnimator {
         private final List<View> mViews = new ArrayList<>();
         private final ValueAnimator mAnimator;
@@ -806,30 +793,31 @@
 
         private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
                 new ValueAnimator.AnimatorUpdateListener() {
-            float mLastT = -1;
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                float t = valueAnimator.getAnimatedFraction();
-                final int viewCount = mViews.size();
-                int height = (Integer) valueAnimator.getAnimatedValue();
-                for (int i = 0; i < viewCount; i++) {
-                    View v = mViews.get(i);
-                    if (v instanceof HeightOverrideable) {
-                        ((HeightOverrideable) v).setHeightOverride(height);
-                    } else {
-                        v.setBottom(v.getTop() + height);
+                    float mLastT = -1;
+
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                        float t = valueAnimator.getAnimatedFraction();
+                        final int viewCount = mViews.size();
+                        int height = (Integer) valueAnimator.getAnimatedValue();
+                        for (int i = 0; i < viewCount; i++) {
+                            View v = mViews.get(i);
+                            if (v instanceof HeightOverrideable) {
+                                ((HeightOverrideable) v).setHeightOverride(height);
+                            } else {
+                                v.setBottom(v.getTop() + height);
+                            }
+                        }
+                        if (t == 0f) {
+                            mListener.onAnimationAtStart();
+                        } else if (t == 1f) {
+                            mListener.onAnimationAtEnd();
+                        } else if (mLastT <= 0 || mLastT == 1) {
+                            mListener.onAnimationStarted();
+                        }
+                        mLastT = t;
                     }
-                }
-                if (t == 0f) {
-                    mListener.onAnimationAtStart();
-                } else if (t == 1f) {
-                    mListener.onAnimationAtEnd();
-                } else if (mLastT <= 0 || mLastT == 1) {
-                    mListener.onAnimationStarted();
-                }
-                mLastT = t;
-            }
-        };
+                };
 
         HeightExpansionAnimator(TouchAnimator.Listener listener, int startHeight, int endHeight) {
             mListener = listener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index b02efba..de11d56 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -39,8 +39,15 @@
         mBackground = (TransitionDrawable) detail.getBackground();
     }
 
-    public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
-        updateCircularClip(true /* animate */, x, y, in, listener);
+    /**
+     * @param x x position where animation should originate
+     * @param y y position where animation should originate
+     * @param in whether animating in or out
+     * @param listener Animation listener. Called whether or not {@code animate} is true.
+     * @return the duration of the circular animator
+     */
+    public long animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+        return updateCircularClip(true /* animate */, x, y, in, listener);
     }
 
     /**
@@ -50,8 +57,9 @@
      * @param y y position where animation should originate
      * @param in whether animating in or out
      * @param listener Animation listener. Called whether or not {@code animate} is true.
+     * @return the duration of the circular animator
      */
-    public void updateCircularClip(boolean animate, int x, int y, boolean in,
+    public long updateCircularClip(boolean animate, int x, int y, boolean in,
             AnimatorListener listener) {
         if (mAnimator != null) {
             mAnimator.cancel();
@@ -87,6 +95,7 @@
             mAnimator.addListener(mGoneOnEnd);
         }
         mAnimator.start();
+        return mAnimator.getDuration();
     }
 
     private final Runnable mReverseBackground = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index b31e472..3820500 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -34,6 +34,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import androidx.annotation.FloatRange;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Lifecycle;
@@ -166,6 +167,13 @@
     // visible;
     private boolean mQsVisible;
 
+    /**
+     * Whether the notification panel uses the full width of the screen.
+     *
+     * Usually {@code true} on small screens, and {@code false} on large screens.
+     */
+    private boolean mIsNotificationPanelFullWidth;
+
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             QSTileHost qsTileHost,
@@ -565,21 +573,22 @@
     @Override
     public void setInSplitShade(boolean inSplitShade) {
         mInSplitShade = inSplitShade;
-        mQSAnimator.setTranslateWhileExpanding(inSplitShade);
         updateShowCollapsedOnKeyguard();
         updateQsState();
     }
 
     @Override
-    public void setTransitionToFullShadeAmount(float pxAmount, float progress) {
-        boolean isTransitioningToFullShade = pxAmount > 0;
+    public void setTransitionToFullShadeProgress(
+            boolean isTransitioningToFullShade,
+            @FloatRange(from = 0.0, to = 1.0) float qsTransitionFraction,
+            @FloatRange(from = 0.0, to = 1.0) float qsSquishinessFraction) {
         if (isTransitioningToFullShade != mTransitioningToFullShade) {
             mTransitioningToFullShade = isTransitioningToFullShade;
             updateShowCollapsedOnKeyguard();
         }
-        mFullShadeProgress = progress;
+        mFullShadeProgress = qsTransitionFraction;
         setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
-                isTransitioningToFullShade ? progress : mSquishinessFraction);
+                isTransitioningToFullShade ? qsSquishinessFraction : mSquishinessFraction);
     }
 
     @Override
@@ -598,12 +607,16 @@
     }
 
     @Override
+    public void setIsNotificationPanelFullWidth(boolean isFullWidth) {
+        mIsNotificationPanelFullWidth = isFullWidth;
+    }
+
+    @Override
     public void setQsExpansion(float expansion, float panelExpansionFraction,
             float proposedTranslation, float squishinessFraction) {
         float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
-        float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
-                ? mFullShadeProgress : panelExpansionFraction;
-        setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1);
+        float alphaProgress = calculateAlphaProgress(panelExpansionFraction);
+        setAlphaAnimationProgress(alphaProgress);
         mContainer.setExpansion(expansion);
         final float translationScaleY = (mInSplitShade
                 ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
@@ -655,7 +668,11 @@
         mQSPanelController.setRevealExpansion(expansion);
         mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
         mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
-        mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
+
+        float qsScrollViewTranslation =
+                onKeyguard && !mShowCollapsedOnKeyguard ? panelTranslationY : 0;
+        mQSPanelScrollView.setTranslationY(qsScrollViewTranslation);
+
         if (fullyCollapsed) {
             mQSPanelScrollView.setScrollY(0);
         }
@@ -684,10 +701,43 @@
         } else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
             view.setVisibility((View.VISIBLE));
         }
-        float alpha = mQSPanelController.isBouncerInTransit()
-                ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress)
-                : ShadeInterpolation.getContentAlpha(progress);
-        view.setAlpha(alpha);
+        view.setAlpha(interpolateAlphaAnimationProgress(progress));
+    }
+
+    private float calculateAlphaProgress(float panelExpansionFraction) {
+        if (mIsNotificationPanelFullWidth) {
+            // Small screens. QS alpha is not animated.
+            return 1;
+        }
+        if (mInSplitShade) {
+            // Large screens in landscape.
+            if (mTransitioningToFullShade || isKeyguardState()) {
+                // Always use "mFullShadeProgress" on keyguard, because
+                // "panelExpansionFractions" is always 1 on keyguard split shade.
+                return mFullShadeProgress;
+            } else {
+                return panelExpansionFraction;
+            }
+        }
+        // Large screens in portrait.
+        if (mTransitioningToFullShade) {
+            // Only use this value during the standard lock screen shade expansion. During the
+            // "quick" expansion from top, this value is 0.
+            return mFullShadeProgress;
+        } else {
+            return panelExpansionFraction;
+        }
+    }
+
+    private float interpolateAlphaAnimationProgress(float progress) {
+        if (mQSPanelController.isBouncerInTransit()) {
+            return BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress);
+        }
+        if (isKeyguardState()) {
+            // Alpha progress should be linear on lockscreen shade expansion.
+            return progress;
+        }
+        return ShadeInterpolation.getContentAlpha(progress);
     }
 
     private void updateQsBounds() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 7155626..448e180 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -49,7 +49,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Objects;
 
 /** View that represents the quick settings tile panel (when expanded/pulled down). **/
 public class QSPanel extends LinearLayout implements Tunable {
@@ -291,7 +290,16 @@
                 } else {
                     topOffset = tileHeightOffset;
                 }
-                int top = Objects.requireNonNull(mChildrenLayoutTop.get(child));
+                // Animation can occur before the layout pass, meaning setSquishinessFraction() gets
+                // called before onLayout(). So, a child view could be null because it has not
+                // been added to mChildrenLayoutTop yet (which happens in onLayout()).
+                // We use a continue statement here to catch this NPE because, on the layout pass,
+                // this code will be called again from onLayout() with the populated children views.
+                Integer childLayoutTop = mChildrenLayoutTop.get(child);
+                if (childLayoutTop == null) {
+                    continue;
+                }
+                int top = childLayoutTop;
                 child.setLeftTopRightBottom(child.getLeft(), top + topOffset,
                         child.getRight(), top + topOffset + child.getHeight());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index b20d7ba..67bf300 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -97,7 +97,8 @@
         super(rootView);
         mFooterText = mView.findViewById(R.id.footer_text);
         mPrimaryFooterIcon = mView.findViewById(R.id.primary_footer_icon);
-        mFooterIcon = new Icon.Resource(R.drawable.ic_info_outline);
+        mFooterIcon = new Icon.Resource(
+                R.drawable.ic_info_outline, /* contentDescription= */ null);
         mContext = rootView.getContext();
         mSecurityController = securityController;
         mMainHandler = mainHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index f632274..bd75c75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -75,6 +75,7 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.DialogCuj;
 import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.common.shared.model.ContentDescription;
 import com.android.systemui.common.shared.model.Icon;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Application;
@@ -243,16 +244,17 @@
                 isWorkProfileOn).toString();
 
         Icon icon;
+        ContentDescription contentDescription = null;
         if (isParentalControlsEnabled) {
-            icon = new Icon.Loaded(securityModel.getDeviceAdminIcon());
+            icon = new Icon.Loaded(securityModel.getDeviceAdminIcon(), contentDescription);
         } else if (vpnName != null || vpnNameWorkProfile != null) {
             if (securityModel.isVpnBranded()) {
-                icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn);
+                icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn, contentDescription);
             } else {
-                icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic);
+                icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic, contentDescription);
             }
         } else {
-            icon = new Icon.Resource(R.drawable.ic_info_outline);
+            icon = new Icon.Resource(R.drawable.ic_info_outline, contentDescription);
         }
 
         return new SecurityButtonConfig(icon, text, isClickable);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 8ad0119..cf10c79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -125,9 +125,10 @@
             isShown = true;
             mOpening = true;
             setVisibility(View.VISIBLE);
-            mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
+            long duration = mClipper.animateCircularClip(
+                    mX, mY, true, new ExpandAnimatorListener(tileAdapter));
             mQsContainerController.setCustomizerAnimating(true);
-            mQsContainerController.setCustomizerShowing(true);
+            mQsContainerController.setCustomizerShowing(true, duration);
         }
     }
 
@@ -153,13 +154,14 @@
             // Make sure we're not opening (because we're closing). Nobody can think we are
             // customizing after the next two lines.
             mOpening = false;
+            long duration = 0;
             if (animate) {
-                mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
+                duration = mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
             } else {
                 setVisibility(View.GONE);
             }
             mQsContainerController.setCustomizerAnimating(animate);
-            mQsContainerController.setCustomizerShowing(false);
+            mQsContainerController.setCustomizerShowing(false, duration);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 8dd506e..28ddead 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -31,7 +31,6 @@
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.R
-import com.android.systemui.common.ui.binder.ContentDescriptionViewBinder
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.people.ui.view.PeopleViewBinder.bind
@@ -233,10 +232,8 @@
 
         val icon = model.icon
         val iconView = button.icon
-        val contentDescription = model.contentDescription
 
         IconViewBinder.bind(icon, iconView)
-        ContentDescriptionViewBinder.bind(contentDescription, iconView)
         if (model.iconTint != null) {
             iconView.setColorFilter(model.iconTint, PorterDuff.Mode.SRC_IN)
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
index 4c0879e..2ad0513 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
@@ -18,7 +18,6 @@
 
 import android.annotation.DrawableRes
 import android.view.View
-import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 
 /**
@@ -29,7 +28,6 @@
     val icon: Icon,
     val iconTint: Int?,
     @DrawableRes val background: Int,
-    val contentDescription: ContentDescription,
     // TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog
     // or activity.
     val onClick: (View) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index b556a3e..a935338 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -138,10 +138,12 @@
     /** The model for the settings button. */
     val settings: FooterActionsButtonViewModel =
         FooterActionsButtonViewModel(
-            Icon.Resource(R.drawable.ic_settings),
+            Icon.Resource(
+                R.drawable.ic_settings,
+                ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+            ),
             iconTint = null,
             R.drawable.qs_footer_action_circle,
-            ContentDescription.Resource(R.string.accessibility_quick_settings_settings),
             this::onSettingsButtonClicked,
         )
 
@@ -149,14 +151,16 @@
     val power: FooterActionsButtonViewModel? =
         if (showPowerButton) {
             FooterActionsButtonViewModel(
-                Icon.Resource(android.R.drawable.ic_lock_power_off),
+                Icon.Resource(
+                    android.R.drawable.ic_lock_power_off,
+                    ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+                ),
                 iconTint =
                     Utils.getColorAttrDefaultColor(
                         context,
                         com.android.internal.R.attr.textColorOnAccent,
                     ),
                 R.drawable.qs_footer_action_circle_color,
-                ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
                 this::onPowerButtonClicked,
             )
         } else {
@@ -252,10 +256,12 @@
             }
 
         return FooterActionsButtonViewModel(
-            Icon.Loaded(icon),
+            Icon.Loaded(
+                icon,
+                ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
+            ),
             iconTint,
             R.drawable.qs_footer_action_circle,
-            ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
             this::onUserSwitcherClicked,
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 5842665..e9a6c25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -50,6 +50,7 @@
     protected int mIconSizePx;
     private boolean mAnimationEnabled = true;
     private int mState = -1;
+    private boolean mDisabledByPolicy = false;
     private int mTint;
     @Nullable
     private QSTile.Icon mLastIcon;
@@ -159,14 +160,10 @@
     }
 
     protected void setIcon(ImageView iv, QSTile.State state, boolean allowAnimations) {
-        if (state.disabledByPolicy) {
-            iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
-        } else {
-            iv.clearColorFilter();
-        }
-        if (state.state != mState) {
+        if (state.state != mState || state.disabledByPolicy != mDisabledByPolicy) {
             int color = getColor(state);
             mState = state.state;
+            mDisabledByPolicy = state.disabledByPolicy;
             if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
                 animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
             } else {
@@ -241,8 +238,8 @@
      */
     private static int getIconColorForState(Context context, QSTile.State state) {
         if (state.disabledByPolicy || state.state == Tile.STATE_UNAVAILABLE) {
-            return Utils.applyAlpha(QSTileViewImpl.UNAVAILABLE_ALPHA,
-                    Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary));
+            return Utils.getColorAttrDefaultColor(
+                    context, com.android.internal.R.attr.textColorTertiary);
         } else if (state.state == Tile.STATE_INACTIVE) {
             return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
         } else if (state.state == Tile.STATE_ACTIVE) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 163ee2a..972b243 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -100,14 +100,15 @@
             Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorOnAccent)
     private val colorLabelInactive =
             Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
-    private val colorLabelUnavailable = Utils.applyAlpha(UNAVAILABLE_ALPHA, colorLabelInactive)
+    private val colorLabelUnavailable =
+        Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorTertiary)
 
     private val colorSecondaryLabelActive =
             Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondaryInverse)
     private val colorSecondaryLabelInactive =
             Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondary)
     private val colorSecondaryLabelUnavailable =
-            Utils.applyAlpha(UNAVAILABLE_ALPHA, colorSecondaryLabelInactive)
+        Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorTertiary)
 
     private lateinit var label: TextView
     protected lateinit var secondaryLabel: TextView
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 05b3420..c65bd9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -31,7 +31,6 @@
 import com.android.systemui.controls.dagger.ControlsComponent
 import com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE
 import com.android.systemui.controls.management.ControlsListingController
-import com.android.systemui.controls.ui.ControlsActivity
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -42,7 +41,6 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.statusbar.policy.KeyguardStateController
 import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
 
@@ -55,8 +53,7 @@
     statusBarStateController: StatusBarStateController,
     activityStarter: ActivityStarter,
     qsLogger: QSLogger,
-    private val controlsComponent: ControlsComponent,
-    private val keyguardStateController: KeyguardStateController
+    private val controlsComponent: ControlsComponent
 ) : QSTileImpl<QSTile.State>(
         host,
         backgroundLooper,
@@ -105,7 +102,8 @@
         }
 
         val intent = Intent().apply {
-            component = ComponentName(mContext, ControlsActivity::class.java)
+            component = ComponentName(mContext, controlsComponent.getControlsUiController().get()
+                .resolveActivity())
             addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
             putExtra(ControlsUiController.EXTRA_ANIMATE, true)
         }
@@ -127,10 +125,15 @@
         state.icon = icon
         if (controlsComponent.isEnabled() && hasControlsApps.get()) {
             if (controlsComponent.getVisibility() == AVAILABLE) {
-                val structure = controlsComponent
-                    .getControlsController().get().getPreferredStructure().structure
-                state.state = Tile.STATE_ACTIVE
-                state.secondaryLabel = if (structure == tileLabel) null else structure
+                val structureInfo = controlsComponent
+                    .getControlsController().get().getPreferredStructure()
+                state.state = if (structureInfo.controls.isEmpty()) {
+                    Tile.STATE_INACTIVE
+                } else {
+                    Tile.STATE_ACTIVE
+                }
+                val label = structureInfo.structure
+                state.secondaryLabel = if (label == tileLabel) null else label
             } else {
                 state.state = Tile.STATE_INACTIVE
                 state.secondaryLabel = mContext.getText(R.string.controls_tile_locked)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index e2964ea..f60e066 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles;
 
 import android.app.UiModeManager;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Handler;
@@ -60,9 +61,7 @@
         ConfigurationController.ConfigurationListener,
         BatteryController.BatteryStateChangeCallback {
     public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a");
-    private final Icon mIcon = ResourceIcon.get(
-            com.android.internal.R.drawable.ic_qs_ui_mode_night);
-    private UiModeManager mUiModeManager;
+    private final UiModeManager mUiModeManager;
     private final BatteryController mBatteryController;
     private final LocationController mLocationController;
     @Inject
@@ -82,7 +81,8 @@
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
         mBatteryController = batteryController;
-        mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
+        mUiModeManager = (UiModeManager) host.getUserContext().getSystemService(
+                Context.UI_MODE_SERVICE);
         mLocationController = locationController;
         configurationController.observe(getLifecycle(), this);
         batteryController.observe(getLifecycle(), this);
@@ -155,7 +155,6 @@
         }
         state.value = nightMode;
         state.label = mContext.getString(R.string.quick_settings_ui_mode_night_label);
-        state.icon = mIcon;
         state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
                 ? state.label
                 : TextUtils.concat(state.label, ", ", state.secondaryLabel);
@@ -164,6 +163,9 @@
         } else {
             state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         }
+        state.icon = ResourceIcon.get(state.state == Tile.STATE_ACTIVE
+                ? R.drawable.qs_light_dark_theme_icon_on
+                : R.drawable.qs_light_dark_theme_icon_off);
         state.showRippleEffect = false;
         state.expandedAccessibilityClassName = Switch.class.getName();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 30862b7..3788ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -61,6 +61,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.PatternMatcher;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -174,7 +175,6 @@
     private boolean mBound;
     private boolean mIsEnabled;
     private int mCurrentBoundedUserId = -1;
-    private float mNavBarButtonAlpha;
     private boolean mInputFocusTransferStarted;
     private float mInputFocusTransferStartY;
     private long mInputFocusTransferStartMillis;
@@ -296,12 +296,6 @@
         }
 
         @Override
-        public void setNavBarButtonAlpha(float alpha, boolean animate) {
-            verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
-                    notifyNavBarButtonAlphaChanged(alpha, animate));
-        }
-
-        @Override
         public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
             verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
                     notifyAssistantProgress(progress));
@@ -581,6 +575,12 @@
             AssistUtils assistUtils,
             DumpManager dumpManager) {
         super(broadcastDispatcher);
+
+        // b/241601880: This component shouldn't be running for a non-primary user
+        if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
+            Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
+        }
+
         mContext = context;
         mPipOptional = pipOptional;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
@@ -603,9 +603,6 @@
         mBackAnimation = backAnimation;
         mUiEventLogger = uiEventLogger;
 
-        // Assumes device always starts with back button until launcher tells it that it does not
-        mNavBarButtonAlpha = 1.0f;
-
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
 
         // Listen for nav bar mode changes
@@ -807,7 +804,6 @@
             mConnectionCallbacks.add(listener);
         }
         listener.onConnectionChanged(mOverviewProxy != null);
-        listener.onNavBarButtonAlphaChanged(mNavBarButtonAlpha, false);
     }
 
     @Override
@@ -837,17 +833,10 @@
         if (mOverviewProxy != null) {
             mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
             mOverviewProxy = null;
-            notifyNavBarButtonAlphaChanged(1f, false /* animate */);
             notifyConnectionChanged();
         }
     }
 
-    private void notifyNavBarButtonAlphaChanged(float alpha, boolean animate) {
-        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
-            mConnectionCallbacks.get(i).onNavBarButtonAlphaChanged(alpha, animate);
-        }
-    }
-
     private void notifyHomeRotationEnabled(boolean enabled) {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
             mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled);
@@ -1076,7 +1065,6 @@
         pw.print("  mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
         pw.print("  mWindowCornerRadius="); pw.println(mWindowCornerRadius);
         pw.print("  mSupportsRoundedCornersOnWindows="); pw.println(mSupportsRoundedCornersOnWindows);
-        pw.print("  mNavBarButtonAlpha="); pw.println(mNavBarButtonAlpha);
         pw.print("  mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
         pw.print("  mNavBarMode="); pw.println(mNavBarMode);
         mSysUiState.dump(pw, args);
@@ -1091,8 +1079,6 @@
         default void onQuickScrubStarted() {}
         /** Notify the recents app (overview) is started by 3-button navigation. */
         default void onToggleRecentApps() {}
-        /** Notify changes in the nav bar button alpha */
-        default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
         default void onHomeRotationEnabled(boolean enabled) {}
         default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
         default void onTaskbarAutohideSuspend(boolean suspend) {}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 06c80a1..2ee5f05 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -37,10 +37,12 @@
 import android.text.SpannableStringBuilder;
 import android.text.style.BulletSpan;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.Button;
@@ -54,7 +56,6 @@
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.util.leak.RotationUtils;
 
@@ -67,6 +68,7 @@
 
 public class ScreenPinningRequest implements View.OnClickListener,
         NavigationModeController.ModeChangedListener {
+    private static final String TAG = "ScreenPinningRequest";
 
     private final Context mContext;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -248,9 +250,8 @@
             mLayout.findViewById(R.id.screen_pinning_text_area)
                     .setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
             View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
-            WindowManagerWrapper wm = WindowManagerWrapper.getInstance();
             if (!QuickStepContract.isGesturalMode(mNavBarMode)
-            	    && wm.hasSoftNavigationBar(mContext.getDisplayId()) && !isTablet(mContext)) {
+            	    && hasSoftNavigationBar(mContext.getDisplayId()) && !isTablet(mContext)) {
                 buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
                 swapChildrenIfRtlAndVertical(buttons);
             } else {
@@ -321,6 +322,20 @@
             addView(mLayout, getRequestLayoutParams(rotation));
         }
 
+        /**
+         * @param displayId the id of display to check if there is a software navigation bar.
+         *
+         * @return whether there is a soft nav bar on specific display.
+         */
+        private boolean hasSoftNavigationBar(int displayId) {
+            try {
+                return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(displayId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to check soft navigation bar", e);
+                return false;
+            }
+        }
+
         private void swapChildrenIfRtlAndVertical(View group) {
             if (mContext.getResources().getConfiguration().getLayoutDirection()
                     != View.LAYOUT_DIRECTION_RTL) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
index 246265b..ac5640b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
@@ -24,8 +24,9 @@
 import android.util.Log
 import android.view.DisplayAddress
 import android.view.SurfaceControl
-import android.view.SurfaceControl.DisplayCaptureArgs
-import android.view.SurfaceControl.ScreenshotHardwareBuffer
+import android.window.ScreenCapture
+import android.window.ScreenCapture.DisplayCaptureArgs
+import android.window.ScreenCapture.ScreenshotHardwareBuffer
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -84,6 +85,6 @@
                 .setSize(width, height)
                 .setSourceCrop(crop)
                 .build()
-        return SurfaceControl.captureDisplay(captureArgs)
+        return ScreenCapture.captureDisplay(captureArgs)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index 6b32daf..fe40d4c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -30,6 +30,7 @@
 import com.android.settingslib.Utils
 import com.android.systemui.Dumpable
 import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
@@ -310,6 +311,14 @@
         updateVisibility()
     }
 
+    fun startCustomizingAnimation(show: Boolean, duration: Long) {
+        header.animate()
+                .setDuration(duration)
+                .alpha(if (show) 0f else 1f)
+                .setInterpolator(if (show) Interpolators.ALPHA_OUT else Interpolators.ALPHA_IN)
+                .start()
+    }
+
     private fun loadConstraints() {
         if (header is MotionLayout) {
             // Use resources.getXml instead of passing the resource id due to bug b/205018300
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 91c6a9c..3429b9d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -117,7 +117,6 @@
 import com.android.systemui.camera.CameraGestureHelper;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -140,7 +139,6 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -217,7 +215,6 @@
 import com.android.systemui.util.ListenerSet;
 import com.android.systemui.util.Utils;
 import com.android.systemui.util.time.SystemClock;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
 import java.io.PrintWriter;
@@ -325,9 +322,6 @@
     private final FragmentService mFragmentService;
     private final ScrimController mScrimController;
     private final PrivacyDotViewController mPrivacyDotViewController;
-    private final QuickAccessWalletController mQuickAccessWalletController;
-    private final QRCodeScannerController mQRCodeScannerController;
-    private final ControlsComponent mControlsComponent;
     private final NotificationRemoteInputManager mRemoteInputManager;
 
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -449,6 +443,8 @@
     private boolean mQsTouchAboveFalsingThreshold;
     private int mQsFalsingThreshold;
 
+    /** Indicates drag starting height when swiping down or up on heads-up notifications */
+    private int mHeadsUpStartHeight;
     private HeadsUpTouchHelper mHeadsUpTouchHelper;
     private boolean mListenForHeadsUp;
     private int mNavigationBarBottomHeight;
@@ -651,6 +647,8 @@
 
     /** The drag distance required to fully expand the split shade. */
     private int mSplitShadeFullTransitionDistance;
+    /** The drag distance required to fully transition scrims. */
+    private int mSplitShadeScrimTransitionDistance;
 
     private final NotificationListContainer mNotificationListContainer;
     private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@@ -696,8 +694,8 @@
     };
 
     private final CameraGestureHelper mCameraGestureHelper;
-    private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
-    private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
+    private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
+    private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
 
     @Inject
     public NotificationPanelViewController(NotificationPanelView view,
@@ -746,8 +744,6 @@
             NavigationModeController navigationModeController,
             FragmentService fragmentService,
             ContentResolver contentResolver,
-            QuickAccessWalletController quickAccessWalletController,
-            QRCodeScannerController qrCodeScannerController,
             RecordingController recordingController,
             LargeScreenShadeHeaderController largeScreenShadeHeaderController,
             ScreenOffAnimationController screenOffAnimationController,
@@ -755,7 +751,6 @@
             PanelExpansionStateManager panelExpansionStateManager,
             NotificationRemoteInputManager remoteInputManager,
             Optional<SysUIUnfoldComponent> unfoldComponent,
-            ControlsComponent controlsComponent,
             InteractionJankMonitor interactionJankMonitor,
             QsFrameTranslateController qsFrameTranslateController,
             SysUiState sysUiState,
@@ -768,8 +763,8 @@
             ShadeTransitionController shadeTransitionController,
             SystemClock systemClock,
             CameraGestureHelper cameraGestureHelper,
-            Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
-            Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
+            KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
+            KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) {
         super(view,
                 falsingManager,
                 dozeLog,
@@ -791,9 +786,6 @@
         mVibratorHelper = vibratorHelper;
         mKeyguardMediaController = keyguardMediaController;
         mPrivacyDotViewController = privacyDotViewController;
-        mQuickAccessWalletController = quickAccessWalletController;
-        mQRCodeScannerController = qrCodeScannerController;
-        mControlsComponent = controlsComponent;
         mMetricsLogger = metricsLogger;
         mConfigurationController = configurationController;
         mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
@@ -897,7 +889,7 @@
 
         mQsFrameTranslateController = qsFrameTranslateController;
         updateUserSwitcherFlags();
-        mKeyguardBottomAreaViewModelProvider = keyguardBottomAreaViewModelProvider;
+        mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
         onFinishInflate();
         keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
                 new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -951,7 +943,7 @@
                     }
                 });
         mCameraGestureHelper = cameraGestureHelper;
-        mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
+        mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
     }
 
     @VisibleForTesting
@@ -1064,6 +1056,8 @@
         mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
                 R.dimen.notification_side_paddings);
         mUdfpsMaxYBurnInOffset = mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
+        mSplitShadeScrimTransitionDistance = mResources.getDimensionPixelSize(
+                R.dimen.split_shade_scrim_transition_distance);
     }
 
     private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -1276,17 +1270,7 @@
     }
 
     private void initBottomArea() {
-        if (mFeatureFlags.isEnabled(Flags.MODERN_BOTTOM_AREA)) {
-            mKeyguardBottomArea.init(mKeyguardBottomAreaViewModelProvider.get(), mFalsingManager);
-        } else {
-            // TODO(b/235403546): remove this method call when the new implementation is complete
-            //  and these are not needed.
-            mKeyguardBottomArea.init(
-                    mFalsingManager,
-                    mQuickAccessWalletController,
-                    mControlsComponent,
-                    mQRCodeScannerController);
-        }
+        mKeyguardBottomArea.init(mKeyguardBottomAreaViewModel, mFalsingManager);
     }
 
     @VisibleForTesting
@@ -1342,6 +1326,9 @@
         mIsFullWidth = isFullWidth;
         mScrimController.setClipsQsScrim(isFullWidth);
         mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
+        if (mQs != null) {
+            mQs.setIsNotificationPanelFullWidth(isFullWidth);
+        }
     }
 
     private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -1354,7 +1341,7 @@
         mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         mQsSizeChangeAnimator.addUpdateListener(animation -> {
             requestScrollerTopPaddingUpdate(false /* animate */);
-            requestPanelHeightUpdate();
+            updateExpandedHeightToMaxHeight();
             int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
             mQs.setHeightOverride(height);
         });
@@ -1403,7 +1390,6 @@
         }
 
         mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
-        mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
 
         mStackScrollerMeasuringPass++;
         requestScrollerTopPaddingUpdate(animate);
@@ -1453,7 +1439,7 @@
                 mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
                 mKeyguardStatusViewController.isClockTopAligned());
         mClockPositionAlgorithm.run(mClockPositionResult);
-        mKeyguardBottomAreaInteractorProvider.get().setClockPosition(
+        mKeyguardBottomAreaInteractor.setClockPosition(
                 mClockPositionResult.clockX, mClockPositionResult.clockY);
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
         boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
@@ -2134,7 +2120,7 @@
             mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
             setQsExpandImmediate(true);
             setShowShelfOnly(true);
-            requestPanelHeightUpdate();
+            updateExpandedHeightToMaxHeight();
 
             // Normally, we start listening when the panel is expanded, but here we need to start
             // earlier so the state is already up to date when dragging down.
@@ -2346,7 +2332,7 @@
         // Reset scroll position and apply that position to the expanded height.
         float height = mQsExpansionHeight;
         setQsExpansion(height);
-        requestPanelHeightUpdate();
+        updateExpandedHeightToMaxHeight();
         mNotificationStackScrollLayoutController.checkSnoozeLeavebehind();
 
         // When expanding QS, let's authenticate the user if possible,
@@ -2362,7 +2348,7 @@
         if (changed) {
             mQsExpanded = expanded;
             updateQsState();
-            requestPanelHeightUpdate();
+            updateExpandedHeightToMaxHeight();
             mFalsingCollector.setQsExpanded(expanded);
             mCentralSurfaces.setQsExpanded(expanded);
             mNotificationsQSContainerController.setQsExpanded(expanded);
@@ -2451,8 +2437,8 @@
         final float squishiness;
         if ((mQsExpandImmediate || mQsExpanded) && !mSplitShadeEnabled) {
             squishiness = 1;
-        } else if (mLockscreenShadeTransitionController.getQSDragProgress() > 0) {
-            squishiness = mLockscreenShadeTransitionController.getQSDragProgress();
+        } else if (mTransitioningToFullShadeProgress > 0.0f) {
+            squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction();
         } else {
             squishiness = mNotificationStackScrollLayoutController
                     .getNotificationSquishinessFraction();
@@ -3086,16 +3072,7 @@
         int maxHeight;
         if (mQsExpandImmediate || mQsExpanded || mIsExpanding && mQsExpandedWhenExpandingStarted
                 || mPulsing || mSplitShadeEnabled) {
-            if (mSplitShadeEnabled && mBarState == SHADE) {
-                // Max panel height is used to calculate the fraction of the shade expansion.
-                // Traditionally the value is based on the number of notifications.
-                // On split-shade, we want the required distance to be a specific and constant
-                // value, to make sure the expansion motion has the expected speed.
-                // We also only want this on non-lockscreen for now.
-                maxHeight = mSplitShadeFullTransitionDistance;
-            } else {
-                maxHeight = calculatePanelHeightQsExpanded();
-            }
+            maxHeight = calculatePanelHeightQsExpanded();
         } else {
             maxHeight = calculatePanelHeightShade();
         }
@@ -3296,8 +3273,7 @@
                 getExpandedFraction());
         float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
         alpha *= mBottomAreaShadeAlpha;
-        mKeyguardBottomArea.setComponentAlphas(alpha);
-        mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
+        mKeyguardBottomAreaInteractor.setAlpha(alpha);
         mLockIconViewController.setAlpha(alpha);
     }
 
@@ -3455,6 +3431,31 @@
     }
 
     @Override
+    public int getMaxPanelTransitionDistance() {
+        // Traditionally the value is based on the number of notifications. On split-shade, we want
+        // the required distance to be a specific and constant value, to make sure the expansion
+        // motion has the expected speed. We also only want this on non-lockscreen for now.
+        if (mSplitShadeEnabled && mBarState == SHADE) {
+            boolean transitionFromHeadsUp =
+                    mHeadsUpManager.isTrackingHeadsUp() || mExpandingFromHeadsUp;
+            // heads-up starting height is too close to mSplitShadeFullTransitionDistance and
+            // when dragging HUN transition is already 90% complete. It makes shade become
+            // immediately visible when starting to drag. We want to set distance so that
+            // nothing is immediately visible when dragging (important for HUN swipe up motion) -
+            // 0.4 expansion fraction is a good starting point.
+            if (transitionFromHeadsUp) {
+                double maxDistance = Math.max(mSplitShadeFullTransitionDistance,
+                        mHeadsUpStartHeight * 2.5);
+                return (int) Math.min(getMaxPanelHeight(), maxDistance);
+            } else {
+                return mSplitShadeFullTransitionDistance;
+            }
+        } else {
+            return getMaxPanelHeight();
+        }
+    }
+
+    @Override
     protected boolean isTrackingBlocked() {
         return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
     }
@@ -3496,8 +3497,7 @@
     }
 
     private void updateDozingVisibilities(boolean animate) {
-        mKeyguardBottomArea.setDozing(mDozing, animate);
-        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+        mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
         if (!mDozing && animate) {
             mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
         }
@@ -3654,10 +3654,35 @@
     }
 
     /**
+     * Called when heads-up notification is being dragged up or down to indicate what's the starting
+     * height for shade motion
+     */
+    public void setHeadsUpDraggingStartingHeight(int startHeight) {
+        mHeadsUpStartHeight = startHeight;
+        float scrimMinFraction;
+        if (mSplitShadeEnabled) {
+            boolean highHun = mHeadsUpStartHeight * 2.5 > mSplitShadeScrimTransitionDistance;
+            // if HUN height is higher than 40% of predefined transition distance, it means HUN
+            // is too high for regular transition. In that case we need to calculate transition
+            // distance - here we take scrim transition distance as equal to shade transition
+            // distance. It doesn't result in perfect motion - usually scrim transition distance
+            // should be longer - but it's good enough for HUN case.
+            float transitionDistance =
+                    highHun ? getMaxPanelTransitionDistance() : mSplitShadeFullTransitionDistance;
+            scrimMinFraction = mHeadsUpStartHeight / transitionDistance;
+        } else {
+            int transitionDistance = getMaxPanelHeight();
+            scrimMinFraction = transitionDistance > 0f
+                    ? (float) mHeadsUpStartHeight / transitionDistance : 0f;
+        }
+        setPanelScrimMinFraction(scrimMinFraction);
+    }
+
+    /**
      * Sets the minimum fraction for the panel expansion offset. This may be non-zero in certain
      * cases, such as if there's a heads-up notification.
      */
-    public void setPanelScrimMinFraction(float minFraction) {
+    private void setPanelScrimMinFraction(float minFraction) {
         mMinFraction = minFraction;
         mDepthController.setPanelPullDownMinFraction(mMinFraction);
         mScrimController.setPanelScrimMinFraction(mMinFraction);
@@ -3741,6 +3766,7 @@
             mQs.setHeaderClickable(isQsExpansionEnabled());
             mQs.setOverscrolling(mStackScrollerOverscrolling);
             mQs.setInSplitShade(mSplitShadeEnabled);
+            mQs.setIsNotificationPanelFullWidth(mIsFullWidth);
 
             // recompute internal state when qspanel height changes
             mQs.getView().addOnLayoutChangeListener(
@@ -3799,8 +3825,7 @@
         mView.setDozing(dozing);
         mDozing = dozing;
         mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
-        mKeyguardBottomArea.setDozing(mDozing, animate);
-        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+        mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
         mKeyguardStatusBarViewController.setDozing(mDozing);
 
         if (dozing) {
@@ -3849,7 +3874,6 @@
 
     public void dozeTimeTick() {
         mLockIconViewController.dozeTimeTick();
-        mKeyguardBottomArea.dozeTimeTick();
         mKeyguardStatusViewController.dozeTimeTick();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
@@ -4391,7 +4415,7 @@
             if (mKeyguardShowing) {
                 updateMaxDisplayedNotifications(true);
             }
-            requestPanelHeightUpdate();
+            updateExpandedHeightToMaxHeight();
         }
 
         @Override
@@ -4524,7 +4548,7 @@
             if (mQsExpanded && mQsFullyExpanded) {
                 mQsExpansionHeight = mQsMaxExpansionHeight;
                 requestScrollerTopPaddingUpdate(false /* animate */);
-                requestPanelHeightUpdate();
+                updateExpandedHeightToMaxHeight();
             }
             if (mAccessibilityManager.isEnabled()) {
                 mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
@@ -4672,7 +4696,6 @@
         public void onDozeAmountChanged(float linearAmount, float amount) {
             mInterpolatedDarkAmount = amount;
             mLinearDarkAmount = linearAmount;
-            mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
             positionClockAndNotifications();
         }
     }
@@ -4794,7 +4817,7 @@
             if (mQsExpanded && mQsFullyExpanded) {
                 mQsExpansionHeight = mQsMaxExpansionHeight;
                 requestScrollerTopPaddingUpdate(false /* animate */);
-                requestPanelHeightUpdate();
+                updateExpandedHeightToMaxHeight();
 
                 // Size has changed, start an animation.
                 if (mQsMaxExpansionHeight != oldMaxHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index e93f605..abafecc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -29,6 +29,7 @@
 import android.view.ViewGroup;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.LockIconViewController;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
@@ -138,6 +139,13 @@
         return mView.findViewById(R.id.keyguard_bouncer_container);
     }
 
+    /**
+     * @return Location where to place the KeyguardMessageArea
+     */
+    public AuthKeyguardMessageArea getKeyguardMessageArea() {
+        return mView.findViewById(R.id.keyguard_message_area);
+    }
+
     /** Inflates the {@link R.layout#status_bar_expanded} layout and sets it up. */
     public void setupExpandedStatusBar() {
         mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 2a46776..d6f0de8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -35,6 +35,7 @@
     view: NotificationsQuickSettingsContainer,
     private val navigationModeController: NavigationModeController,
     private val overviewProxyService: OverviewProxyService,
+    private val largeScreenShadeHeaderController: LargeScreenShadeHeaderController,
     private val featureFlags: FeatureFlags,
     @Main private val delayableExecutor: DelayableExecutor
 ) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
@@ -156,9 +157,12 @@
         }
     }
 
-    override fun setCustomizerShowing(showing: Boolean) {
-        isQSCustomizing = showing
-        updateBottomSpacing()
+    override fun setCustomizerShowing(showing: Boolean, animationDuration: Long) {
+        if (showing != isQSCustomizing) {
+            isQSCustomizing = showing
+            largeScreenShadeHeaderController.startCustomizingAnimation(showing, animationDuration)
+            updateBottomSpacing()
+        }
     }
 
     override fun setDetailShowing(showing: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
index 876a1ff..c3f1e57 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
@@ -248,7 +248,7 @@
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onKeyguardFadingAwayChanged() {
-                requestPanelHeightUpdate();
+                updateExpandedHeightToMaxHeight();
             }
         });
         mAmbientState = ambientState;
@@ -397,7 +397,7 @@
         mInitialOffsetOnTouch = expandedHeight;
         mInitialExpandY = newY;
         mInitialExpandX = newX;
-        mInitialTouchFromKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+        mInitialTouchFromKeyguard = mKeyguardStateController.isShowing();
         if (startTracking) {
             mTouchSlopExceeded = true;
             setExpandedHeight(mInitialOffsetOnTouch);
@@ -416,9 +416,7 @@
             float vectorVel = (float) Math.hypot(
                     mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
 
-            final boolean onKeyguard =
-                    mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
-
+            final boolean onKeyguard = mKeyguardStateController.isShowing();
             final boolean expand;
             if (mKeyguardStateController.isKeyguardFadingAway()
                     || (mInitialTouchFromKeyguard && !onKeyguard)) {
@@ -732,7 +730,7 @@
         setExpandedHeightInternal(height);
     }
 
-    protected void requestPanelHeightUpdate() {
+    void updateExpandedHeightToMaxHeight() {
         float currentMaxPanelHeight = getMaxPanelHeight();
 
         if (isFullyCollapsed()) {
@@ -755,6 +753,13 @@
         setExpandedHeight(currentMaxPanelHeight);
     }
 
+    /**
+     * Returns drag down distance after which panel should be fully expanded. Usually it's the
+     * same as max panel height but for large screen devices (especially split shade) we might
+     * want to return different value to shorten drag distance
+     */
+    public abstract int getMaxPanelTransitionDistance();
+
     public void setExpandedHeightInternal(float h) {
         if (isNaN(h)) {
             Log.wtf(TAG, "ExpandedHeight set to NaN");
@@ -765,18 +770,15 @@
                         () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
                 mExpandLatencyTracking = false;
             }
-            float maxPanelHeight = getMaxPanelHeight();
+            float maxPanelHeight = getMaxPanelTransitionDistance();
             if (mHeightAnimator == null) {
                 // Split shade has its own overscroll logic
                 if (mTracking && !mInSplitShade) {
                     float overExpansionPixels = Math.max(0, h - maxPanelHeight);
                     setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
                 }
-                mExpandedHeight = Math.min(h, maxPanelHeight);
-            } else {
-                mExpandedHeight = h;
             }
-
+            mExpandedHeight = Math.min(h, maxPanelHeight);
             // If we are closing the panel and we are almost there due to a slow decelerating
             // interpolator, abort the animation.
             if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
@@ -834,7 +836,7 @@
     protected abstract int getMaxPanelHeight();
 
     public void setExpandedFraction(float frac) {
-        setExpandedHeight(getMaxPanelHeight() * frac);
+        setExpandedHeight(getMaxPanelTransitionDistance() * frac);
     }
 
     public float getExpandedHeight() {
@@ -1031,7 +1033,7 @@
         mHeightAnimator = animator;
         if (animator == null && mPanelUpdateWhenAnimatorEnds) {
             mPanelUpdateWhenAnimatorEnds = false;
-            requestPanelHeightUpdate();
+            updateExpandedHeightToMaxHeight();
         }
     }
 
@@ -1423,7 +1425,7 @@
         @Override
         public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
                 int oldTop, int oldRight, int oldBottom) {
-            requestPanelHeightUpdate();
+            updateExpandedHeightToMaxHeight();
             mHasLayoutedSinceDown = true;
             if (mUpdateFlingOnLayout) {
                 abortAnimations();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index 621a609..9b3fe92 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
 import com.android.systemui.tuner.TunerService
@@ -49,6 +50,7 @@
         private val dockManager: DockManager,
         private val centralSurfaces: CentralSurfaces,
         private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
+        private val statusBarStateController: StatusBarStateController,
         tunerService: TunerService,
         dumpManager: DumpManager
 ) : GestureDetector.SimpleOnGestureListener(), Dumpable {
@@ -74,7 +76,8 @@
     }
 
     override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
-        if (singleTapEnabled &&
+        if (statusBarStateController.isPulsing &&
+                singleTapEnabled &&
                 !dockManager.isDocked &&
                 !falsingManager.isProximityNear &&
                 !falsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)
@@ -89,7 +92,8 @@
     }
 
     override fun onDoubleTap(e: MotionEvent): Boolean {
-        if ((doubleTapEnabled || singleTapEnabled) &&
+        if (statusBarStateController.isPulsing &&
+                (doubleTapEnabled || singleTapEnabled) &&
                 !falsingManager.isProximityNear &&
                 !falsingManager.isFalseDoubleTap
         ) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index afd57da..618c892 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -14,6 +14,7 @@
 import com.android.systemui.statusbar.phone.panelstate.PanelState
 import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.util.LargeScreenUtils
 import java.io.PrintWriter
 import javax.inject.Inject
@@ -28,6 +29,7 @@
     private val scrimController: ScrimController,
     @Main private val resources: Resources,
     private val statusBarStateController: SysuiStatusBarStateController,
+    private val headsUpManager: HeadsUpManager
 ) {
 
     private var inSplitShade = false
@@ -84,7 +86,11 @@
     }
 
     private fun canUseCustomFraction(panelState: Int?) =
-        inSplitShade && isScreenUnlocked() && panelState == STATE_OPENING
+        inSplitShade && isScreenUnlocked() && panelState == STATE_OPENING &&
+                // in case of HUN we can't always use predefined distances to manage scrim
+                // transition because dragDownPxAmount can start from value bigger than
+                // splitShadeScrimTransitionDistance
+                !headsUpManager.isTrackingHeadsUp
 
     private fun isScreenUnlocked() =
         statusBarStateController.currentOrUpcomingState == StatusBarState.SHADE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 47dc5c2..e06c977 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,6 +19,7 @@
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
 import static android.hardware.biometrics.BiometricSourceType.FACE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
@@ -49,6 +50,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
@@ -78,6 +80,7 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.R;
+import com.android.systemui.biometrics.FaceHelpMessageDeferral;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -178,7 +181,8 @@
     private boolean mBatteryPresent = true;
     private long mChargingTimeRemaining;
     private String mBiometricErrorMessageToShowOnScreenOn;
-    private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
+    private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
+    private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral;
     private boolean mInited;
 
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -228,7 +232,8 @@
             LockPatternUtils lockPatternUtils,
             ScreenLifecycle screenLifecycle,
             KeyguardBypassController keyguardBypassController,
-            AccessibilityManager accessibilityManager) {
+            AccessibilityManager accessibilityManager,
+            FaceHelpMessageDeferral faceHelpMessageDeferral) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
         mDevicePolicyManager = devicePolicyManager;
@@ -249,11 +254,12 @@
         mScreenLifecycle = screenLifecycle;
         mScreenLifecycle.addObserver(mScreenObserver);
 
-        mCoExFaceHelpMsgIdsToShow = new HashSet<>();
+        mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
+        mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
         int[] msgIds = context.getResources().getIntArray(
                 com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
         for (int msgId : msgIds) {
-            mCoExFaceHelpMsgIdsToShow.add(msgId);
+            mCoExFaceAcquisitionMsgIdsToShow.add(msgId);
         }
 
         mHandler = new Handler(mainLooper) {
@@ -687,11 +693,11 @@
     /**
      * Returns the indication text indicating that trust has been granted.
      *
-     * @return {@code null} or an empty string if a trust indication text should not be shown.
+     * @return an empty string if a trust indication text should not be shown.
      */
     @VisibleForTesting
     String getTrustGrantedIndication() {
-        return TextUtils.isEmpty(mTrustGrantedIndication)
+        return mTrustGrantedIndication == null
                 ? mContext.getString(R.string.keyguard_indication_trust_unlocked)
                 : mTrustGrantedIndication.toString();
     }
@@ -927,7 +933,7 @@
                 return; // udfps affordance is highlighted, no need to show action to unlock
             } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) {
                 String message = mContext.getString(R.string.keyguard_retry);
-                mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
+                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState);
             }
         } else {
             final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(
@@ -990,7 +996,7 @@
                 mTopIndicationView == null ? null : mTopIndicationView.getText()));
         pw.println("  computePowerIndication(): " + computePowerIndication());
         pw.println("  trustGrantedIndication: " + getTrustGrantedIndication());
-        pw.println("    mCoExFaceHelpMsgIdsToShow=" + mCoExFaceHelpMsgIdsToShow);
+        pw.println("    mCoExFaceHelpMsgIdsToShow=" + mCoExFaceAcquisitionMsgIdsToShow);
         mRotateTextViewController.dump(pw, args);
     }
 
@@ -1036,8 +1042,22 @@
         }
 
         @Override
+        public void onBiometricAcquired(BiometricSourceType biometricSourceType, int acquireInfo) {
+            if (biometricSourceType == FACE) {
+                mFaceAcquiredMessageDeferral.processFrame(acquireInfo);
+            }
+        }
+
+        @Override
         public void onBiometricHelp(int msgId, String helpString,
                 BiometricSourceType biometricSourceType) {
+            if (biometricSourceType == FACE) {
+                mFaceAcquiredMessageDeferral.updateMessage(msgId, helpString);
+                if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) {
+                    return;
+                }
+            }
+
             // TODO(b/141025588): refactor to reduce repetition of code/comments
             // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
             // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
@@ -1055,19 +1075,24 @@
             final boolean isUnlockWithFingerprintPossible =
                     mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
                             getCurrentUser());
-            if (faceAuthSoftError
-                    && isUnlockWithFingerprintPossible
-                    && !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
+            final boolean isCoExFaceAcquisitionMessage =
+                    faceAuthSoftError && isUnlockWithFingerprintPossible;
+            if (isCoExFaceAcquisitionMessage && !mCoExFaceAcquisitionMsgIdsToShow.contains(msgId)) {
                 if (DEBUG) {
                     Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
                             + ", due to co-ex logic");
                 }
                 return;
             } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
+                mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
                         mInitialTextColorState);
             } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
-                if (faceAuthFailed && isUnlockWithFingerprintPossible) {
+                if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
+                    showBiometricMessage(
+                            helpString,
+                            mContext.getString(R.string.keyguard_suggest_fingerprint)
+                    );
+                } else if (faceAuthFailed && isUnlockWithFingerprintPossible) {
                     showBiometricMessage(
                             mContext.getString(R.string.keyguard_face_failed),
                             mContext.getString(R.string.keyguard_suggest_fingerprint)
@@ -1088,43 +1113,65 @@
         }
 
         @Override
+        public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
+            if (biometricSourceType == FACE) {
+                mFaceAcquiredMessageDeferral.reset();
+            }
+        }
+
+        @Override
         public void onBiometricError(int msgId, String errString,
                 BiometricSourceType biometricSourceType) {
-            if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
-                return;
+            CharSequence deferredFaceMessage = null;
+            if (biometricSourceType == FACE) {
+                if (msgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT) {
+                    deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
+                    if (DEBUG) {
+                        Log.d(TAG, "showDeferredFaceMessage msgId=" + deferredFaceMessage);
+                    }
+                }
+                mFaceAcquiredMessageDeferral.reset();
             }
 
-            if (biometricSourceType == FACE
-                    && msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
-                // suppress all face UNABLE_TO_PROCESS errors
+            if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
                 if (DEBUG) {
-                    Log.d(TAG, "skip showing FACE_ERROR_UNABLE_TO_PROCESS errString="
-                            + errString);
+                    Log.d(TAG, "suppressingBiometricError msgId=" + msgId
+                            + " source=" + biometricSourceType);
                 }
-            } else if (biometricSourceType == FACE
-                    && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+            } else if (biometricSourceType == FACE && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+                // Co-ex: show deferred message OR nothing
                 if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                        getCurrentUser())) {
-                    // no message if fingerprint is also enrolled
+                        KeyguardUpdateMonitor.getCurrentUser())) {
+                    // if we're on the lock screen (bouncer isn't showing), show the deferred msg
+                    if (deferredFaceMessage != null
+                            && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
+                        showBiometricMessage(
+                                deferredFaceMessage,
+                                mContext.getString(R.string.keyguard_suggest_fingerprint)
+                        );
+                        return;
+                    }
+
+                    // otherwise, don't show any message
                     if (DEBUG) {
                         Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic");
                     }
                     return;
                 }
 
-                // The face timeout message is not very actionable, let's ask the user to
+                // Face-only: The face timeout message is not very actionable, let's ask the user to
                 // manually retry.
-                if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
-                    mStatusBarKeyguardViewManager.showBouncerMessage(
-                            mContext.getResources().getString(R.string.keyguard_try_fingerprint),
-                            mInitialTextColorState
+                if (deferredFaceMessage != null) {
+                    showBiometricMessage(
+                            deferredFaceMessage,
+                            mContext.getString(R.string.keyguard_unlock)
                     );
                 } else {
                     // suggest swiping up to unlock (try face auth again or swipe up to bouncer)
                     showActionToUnlock();
                 }
             } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
+                mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState);
             } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 showBiometricMessage(errString);
             } else {
@@ -1134,8 +1181,9 @@
 
         private boolean shouldSuppressBiometricError(int msgId,
                 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
-            if (biometricSourceType == BiometricSourceType.FINGERPRINT)
+            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                 return shouldSuppressFingerprintError(msgId, updateMonitor);
+            }
             if (biometricSourceType == FACE) {
                 return shouldSuppressFaceError(msgId, updateMonitor);
             }
@@ -1161,7 +1209,8 @@
             // check of whether non-strong biometric is allowed
             return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
                     && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
-                    || msgId == FaceManager.FACE_ERROR_CANCELED);
+                    || msgId == FaceManager.FACE_ERROR_CANCELED
+                    || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS);
         }
 
 
@@ -1200,10 +1249,11 @@
                 boolean isStrongBiometric) {
             super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
             hideBiometricMessage();
-
-            if (biometricSourceType == FACE
-                    && !mKeyguardBypassController.canBypass()) {
-                showActionToUnlock();
+            if (biometricSourceType == FACE) {
+                mFaceAcquiredMessageDeferral.reset();
+                if (!mKeyguardBypassController.canBypass()) {
+                    showActionToUnlock();
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
new file mode 100644
index 0000000..62c225b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.content.Context
+import android.util.IndentingPrintWriter
+import android.util.MathUtils
+import androidx.annotation.FloatRange
+import androidx.annotation.Px
+import com.android.systemui.R
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlin.math.max
+
+/** Responsible for the QS components during the lockscreen shade transition. */
+class LockscreenShadeQsTransitionController
+@AssistedInject
+constructor(
+    context: Context,
+    configurationController: ConfigurationController,
+    dumpManager: DumpManager,
+    @Assisted private val qsProvider: () -> QS,
+) : AbstractLockscreenShadeTransitionController(context, configurationController, dumpManager) {
+
+    private val qs: QS
+        get() = qsProvider()
+
+    /**
+     * The progress fraction of the QS transition during lockscreen shade expansion.
+     *
+     * Note that this value might be 0 for some time when the expansion is already in progress,
+     * since there is a transition start delay for QS on some device configurations. For this
+     * reason, don't use this value to check whether the shade expansion is in progress.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    var qsTransitionFraction = 0f
+        private set
+
+    /**
+     * The fraction of the QS "squish" transition progress during lockscreen shade expansion.
+     *
+     * Note that in some device configurations (large screens) this value can start at a value
+     * greater than 0. For this reason don't use this value to check whether the QS transition has
+     * started or not.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    var qsSquishTransitionFraction = 0f
+        private set
+
+    /**
+     * The drag down amount, in pixels __for the QS transition__, also taking into account the
+     * [qsTransitionStartDelay].
+     *
+     * Since it takes into account the start delay, it is __not__ the same as the raw drag down
+     * amount from the shade expansion.
+     */
+    @Px private var qsDragDownAmount = 0f
+
+    /**
+     * Distance it takes for the QS transition to complete during the lockscreen shade expansion.
+     */
+    @Px private var qsTransitionDistance = 0
+
+    /** Distance delay for the QS transition to start during the lockscreen shade expansion. */
+    @Px private var qsTransitionStartDelay = 0
+
+    /**
+     * Distance that it takes to complete the QS "squish" transition during the lockscreen shade
+     * expansion.
+     */
+    @Px private var qsSquishTransitionDistance = 0
+
+    /**
+     * Whether the transition to full shade is in progress. Might be `true` even though
+     * [qsTransitionFraction] is still 0, due to [qsTransitionStartDelay].
+     */
+    private var isTransitioningToFullShade = false
+
+    /**
+     * The fraction at which the QS "squish" transition should start during the lockscreen shade
+     * expansion.
+     *
+     * 0 is fully collapsed, 1 is fully expanded.
+     */
+    @FloatRange(from = 0.0, to = 1.0) private var qsSquishStartFraction = 0f
+
+    override fun updateResources() {
+        qsTransitionDistance =
+            context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance)
+        qsTransitionStartDelay =
+            context.resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_delay)
+        qsSquishTransitionDistance =
+            context.resources.getDimensionPixelSize(
+                R.dimen.lockscreen_shade_qs_squish_transition_distance
+            )
+        qsSquishStartFraction =
+            context.resources.getFloat(R.dimen.lockscreen_shade_qs_squish_start_fraction)
+
+        qsSquishTransitionFraction = max(qsSquishTransitionFraction, qsSquishStartFraction)
+    }
+
+    override fun onDragDownAmountChanged(dragDownAmount: Float) {
+        qsDragDownAmount = dragDownAmount - qsTransitionStartDelay
+        qsTransitionFraction = MathUtils.saturate(qsDragDownAmount / qsTransitionDistance)
+        qsSquishTransitionFraction =
+            MathUtils.lerp(
+                /* start= */ qsSquishStartFraction,
+                /* stop= */ 1f,
+                /* amount= */ MathUtils.saturate(qsDragDownAmount / qsSquishTransitionDistance)
+            )
+        isTransitioningToFullShade = dragDownAmount > 0.0f
+        qs.setTransitionToFullShadeProgress(
+            isTransitioningToFullShade,
+            qsTransitionFraction,
+            qsSquishTransitionFraction
+        )
+    }
+
+    override fun dump(pw: IndentingPrintWriter) {
+        pw.println(
+            """
+            Resources:
+              qsTransitionDistance: $qsTransitionDistance
+              qsTransitionStartDelay: $qsTransitionStartDelay
+              qsSquishTransitionDistance: $qsSquishTransitionDistance
+              qsSquishStartFraction: $qsSquishStartFraction
+            State:
+              dragDownAmount: $dragDownAmount
+              qsDragDownAmount: $qsDragDownAmount
+              qsDragFraction: $qsTransitionFraction
+              qsSquishFraction: $qsSquishTransitionFraction
+              isTransitioningToFullShade: $isTransitioningToFullShade
+        """.trimIndent()
+        )
+    }
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(qsProvider: () -> QS): LockscreenShadeQsTransitionController
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 74d8f1b..8006931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -2,7 +2,6 @@
 
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
 import android.animation.ValueAnimator
 import android.content.Context
 import android.content.res.Configuration
@@ -12,6 +11,7 @@
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewConfiguration
+import androidx.annotation.FloatRange
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
 import com.android.systemui.ExpandHelper
@@ -69,7 +69,8 @@
     wakefulnessLifecycle: WakefulnessLifecycle,
     configurationController: ConfigurationController,
     falsingManager: FalsingManager,
-    dumpManager: DumpManager
+    dumpManager: DumpManager,
+    qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
 ) : Dumpable {
     private var pulseHeight: Float = 0f
     @get:VisibleForTesting
@@ -121,12 +122,6 @@
     private var notificationShelfTransitionDistance = 0
 
     /**
-     * Distance that the full shade transition takes in order for the Quick Settings to fully fade
-     * and expand.
-     */
-    private var qsTransitionDistance = 0
-
-    /**
      * Distance that the full shade transition takes in order for depth of the wallpaper to fully
      * change.
      */
@@ -189,6 +184,18 @@
         keyguardTransitionControllerFactory.create(notificationPanelController)
     }
 
+    private val qsTransitionController = qsTransitionControllerFactory.create { qS }
+
+    /** See [LockscreenShadeQsTransitionController.qsTransitionFraction].*/
+    @get:FloatRange(from = 0.0, to = 1.0)
+    val qSDragProgress: Float
+        get() = qsTransitionController.qsTransitionFraction
+
+    /** See [LockscreenShadeQsTransitionController.qsSquishTransitionFraction].*/
+    @get:FloatRange(from = 0.0, to = 1.0)
+    val qsSquishTransitionFraction: Float
+        get() = qsTransitionController.qsSquishTransitionFraction
+
     /**
      * [LockScreenShadeOverScroller] property that delegates to either
      * [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller].
@@ -243,8 +250,6 @@
             R.dimen.lockscreen_shade_transition_by_tap_distance)
         notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_notif_shelf_transition_distance)
-        qsTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_qs_transition_distance)
         depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
                 R.dimen.lockscreen_shade_depth_controller_transition_distance)
         udfpsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -412,8 +417,7 @@
                         MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
                     nsslController.setTransitionToFullShadeAmount(fractionToShade)
 
-                    qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance)
-                    qS.setTransitionToFullShadeAmount(field, qSDragProgress)
+                    qsTransitionController.dragDownAmount = value
 
                     notificationPanelController.setTransitionToFullShadeAmount(field,
                             false /* animate */, 0 /* delay */)
@@ -427,12 +431,6 @@
             }
         }
 
-    /**
-     * The drag progress of the quick settings drag down amount
-     */
-    var qSDragProgress = 0f
-        private set
-
     private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
         if (depthControllerTransitionDistance == 0) { // split shade
             depthController.transitionToFullShadeProgress = 0f
@@ -705,7 +703,6 @@
             it.println("pulseHeight: $pulseHeight")
             it.println("useSplitShade: $useSplitShade")
             it.println("dragDownAmount: $dragDownAmount")
-            it.println("qSDragProgress: $qSDragProgress")
             it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled")
             it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded")
             it.println("isWakingToShadeLocked: $isWakingToShadeLocked")
@@ -880,15 +877,22 @@
         child.actualHeight = (child.collapsedHeight + rubberband).toInt()
     }
 
-    private fun cancelChildExpansion(child: ExpandableView) {
+    @VisibleForTesting
+    fun cancelChildExpansion(
+            child: ExpandableView,
+            animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS
+    ) {
         if (child.actualHeight == child.collapsedHeight) {
             expandCallback.setUserLockedChild(child, false)
             return
         }
-        val anim = ObjectAnimator.ofInt(child, "actualHeight",
-                child.actualHeight, child.collapsedHeight)
+        val anim = ValueAnimator.ofInt(child.actualHeight, child.collapsedHeight)
         anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
-        anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS
+        anim.duration = animationDuration
+        anim.addUpdateListener { animation: ValueAnimator ->
+            // don't use reflection, because the `actualHeight` field may be obfuscated
+            child.actualHeight = animation.animatedValue as Int
+        }
         anim.addListener(object : AnimatorListenerAdapter() {
             override fun onAnimationEnd(animation: Animator) {
                 expandCallback.setUserLockedChild(child, false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index f6c4a31..cb13fcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -81,7 +81,6 @@
     }
 
     lateinit var root: View
-    private var blurRoot: View? = null
     private var keyguardAnimator: Animator? = null
     private var notificationAnimator: Animator? = null
     private var updateScheduled: Boolean = false
@@ -235,7 +234,7 @@
 
         val opaque = scrimsVisible && !blursDisabledForAppLaunch
         Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur)
-        blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, opaque)
+        blurUtils.applyBlur(root.viewRootImpl, blur, opaque)
         lastAppliedBlur = blur
         wallpaperController.setNotificationShadeZoom(zoomOut)
         listeners.forEach {
@@ -271,7 +270,6 @@
                     override fun onAnimationEnd(animation: Animator?) {
                         keyguardAnimator = null
                         wakeAndUnlockBlurRadius = 0f
-                        scheduleUpdate()
                     }
                 })
                 start()
@@ -302,7 +300,6 @@
 
         override fun onDozeAmountChanged(linear: Float, eased: Float) {
             wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
-            scheduleUpdate()
         }
     }
 
@@ -439,12 +436,11 @@
         shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized).toInt())
     }
 
-    private fun scheduleUpdate(viewToBlur: View? = null) {
+    private fun scheduleUpdate() {
         if (updateScheduled) {
             return
         }
         updateScheduled = true
-        blurRoot = viewToBlur
         choreographer.postFrameCallback(updateBlurCallback)
     }
 
@@ -495,16 +491,11 @@
          */
         private var pendingRadius = -1
 
-        /**
-         * View on {@link Surface} that wants depth.
-         */
-        private var view: View? = null
-
         private var springAnimation = SpringAnimation(this, object :
                 FloatPropertyCompat<DepthAnimation>("blurRadius") {
             override fun setValue(rect: DepthAnimation?, value: Float) {
                 radius = value
-                scheduleUpdate(view)
+                scheduleUpdate()
             }
 
             override fun getValue(rect: DepthAnimation?): Float {
@@ -519,11 +510,10 @@
             springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
         }
 
-        fun animateTo(newRadius: Int, viewToBlur: View? = null) {
-            if (pendingRadius == newRadius && view == viewToBlur) {
+        fun animateTo(newRadius: Int) {
+            if (pendingRadius == newRadius) {
                 return
             }
-            view = viewToBlur
             pendingRadius = newRadius
             springAnimation.animateToFinalPosition(newRadius.toFloat())
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index cea3deb..41c0367 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -90,6 +92,12 @@
         super(context, attrs);
     }
 
+    @VisibleForTesting
+    public NotificationShelf(Context context, AttributeSet attrs, boolean showNotificationShelf) {
+        super(context, attrs);
+        mShowNotificationShelf = showNotificationShelf;
+    }
+
     @Override
     @VisibleForTesting
     public void onFinishInflate() {
@@ -175,7 +183,11 @@
 
             if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
                 float expansion = ambientState.getExpansionFraction();
-                viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+                if (ambientState.isBouncerInTransit()) {
+                    viewState.alpha = aboutToShowBouncerProgress(expansion);
+                } else {
+                    viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+                }
             } else {
                 viewState.alpha = 1f - ambientState.getHideAmount();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 6302ef1..bbff046 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -18,7 +18,7 @@
 
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
-import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
 import android.content.Context
 import android.content.res.Configuration
 import android.os.PowerManager
@@ -28,6 +28,7 @@
 import android.view.MotionEvent
 import android.view.VelocityTracker
 import android.view.ViewConfiguration
+import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
@@ -276,15 +277,22 @@
         }
     }
 
-    private fun reset(child: ExpandableView) {
+    @VisibleForTesting
+    fun reset(
+            child: ExpandableView,
+            animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+    ) {
         if (child.actualHeight == child.collapsedHeight) {
             setUserLocked(child, false)
             return
         }
-        val anim = ObjectAnimator.ofInt(child, "actualHeight",
-                child.actualHeight, child.collapsedHeight)
+        val anim = ValueAnimator.ofInt(child.actualHeight, child.collapsedHeight)
         anim.interpolator = Interpolators.FAST_OUT_SLOW_IN
-        anim.duration = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+        anim.duration = animationDuration
+        anim.addUpdateListener { animation: ValueAnimator ->
+            // don't use reflection, because the `actualHeight` field may be obfuscated
+            child.actualHeight = animation.animatedValue as Int
+        }
         anim.addListener(object : AnimatorListenerAdapter() {
             override fun onAnimationEnd(animation: Animator) {
                 setUserLocked(child, false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 31b21c9..553826d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -136,7 +136,7 @@
         headsUpManager.removeNotification(notificationKey, true /* releaseImmediately */, animate)
     }
 
-    override fun onLaunchAnimationCancelled() {
+    override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
         // TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
         // here?
         notificationShadeWindowViewController.setExpandAnimationRunning(false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 3627b40..52f4c1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -144,11 +144,6 @@
         public void invalidateNotifications(String reason) {
             mNotifFilter.invalidateList(reason);
         }
-
-        @Override
-        public void maybeCancelSummary(NotificationEntry entry) {
-            // no-op
-        }
     };
 
     private boolean isInterceptingDismissal(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index ba26cfa..df81c0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1369,6 +1369,8 @@
         }
         ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button);
         View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
+        LinearLayout actionListMarginTarget = layout.findViewById(
+                com.android.internal.R.id.notification_action_list_margin_target);
         if (bubbleButton == null || actionContainer == null) {
             return;
         }
@@ -1393,6 +1395,16 @@
             bubbleButton.setOnClickListener(mContainingNotification.getBubbleClickListener());
             bubbleButton.setVisibility(VISIBLE);
             actionContainer.setVisibility(VISIBLE);
+            // Set notification_action_list_margin_target's bottom margin to 0 when showing bubble
+            if (actionListMarginTarget != null) {
+                ViewGroup.LayoutParams lp = actionListMarginTarget.getLayoutParams();
+                if (lp instanceof ViewGroup.MarginLayoutParams) {
+                    final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
+                    if (mlp.bottomMargin > 0) {
+                        mlp.setMargins(mlp.leftMargin, mlp.topMargin, mlp.rightMargin, 0);
+                    }
+                }
+            }
         } else  {
             bubbleButton.setVisibility(GONE);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ea28452..ce465bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.util.MathUtils;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
@@ -137,7 +139,17 @@
      * True right after we swipe up on lockscreen and have not finished the fling down that follows.
      * False when we stop flinging or leave lockscreen.
      */
-    private boolean mNeedFlingAfterLockscreenSwipeUp = false;
+    private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false;
+
+    @VisibleForTesting
+    public boolean isFlingRequiredAfterLockScreenSwipeUp() {
+        return mIsFlingRequiredAfterLockScreenSwipeUp;
+    }
+
+    @VisibleForTesting
+    public void setFlingRequiredAfterLockScreenSwipeUp(boolean value) {
+        mIsFlingRequiredAfterLockScreenSwipeUp = value;
+    }
 
     /**
      * @return Height of the notifications panel without top padding when expansion completes.
@@ -181,7 +193,7 @@
     public void setSwipingUp(boolean isSwipingUp) {
         if (!isSwipingUp && mIsSwipingUp) {
             // Just stopped swiping up.
-            mNeedFlingAfterLockscreenSwipeUp = true;
+            mIsFlingRequiredAfterLockScreenSwipeUp = true;
         }
         mIsSwipingUp = isSwipingUp;
     }
@@ -196,10 +208,10 @@
     /**
      * @param isFlinging Whether we are flinging the shade open or closed.
      */
-    public void setIsFlinging(boolean isFlinging) {
+    public void setFlinging(boolean isFlinging) {
         if (isOnKeyguard() && !isFlinging && mIsFlinging) {
             // Just stopped flinging.
-            mNeedFlingAfterLockscreenSwipeUp = false;
+            mIsFlingRequiredAfterLockScreenSwipeUp = false;
         }
         mIsFlinging = isFlinging;
     }
@@ -508,7 +520,7 @@
 
     public void setStatusBarState(int statusBarState) {
         if (mStatusBarState != StatusBarState.KEYGUARD) {
-            mNeedFlingAfterLockscreenSwipeUp = false;
+            mIsFlingRequiredAfterLockScreenSwipeUp = false;
         }
         mStatusBarState = statusBarState;
     }
@@ -576,7 +588,7 @@
      * @return Whether we need to do a fling down after swiping up on lockscreen.
      */
     public boolean isFlingingAfterSwipeUpOnLockscreen() {
-        return mIsFlinging && mNeedFlingAfterLockscreenSwipeUp;
+        return mIsFlinging && mIsFlingRequiredAfterLockScreenSwipeUp;
     }
 
     /**
@@ -744,7 +756,8 @@
         pw.println("mIsSwipingUp=" + mIsSwipingUp);
         pw.println("mPanelTracking=" + mPanelTracking);
         pw.println("mIsFlinging=" + mIsFlinging);
-        pw.println("mNeedFlingAfterLockscreenSwipeUp=" + mNeedFlingAfterLockscreenSwipeUp);
+        pw.println("mIsFlingRequiredAfterLockScreenSwipeUp="
+                + mIsFlingRequiredAfterLockScreenSwipeUp);
         pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements);
         pw.println("mBaseZHeight=" + mBaseZHeight);
     }
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 1fb265f..5fbaa51 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
@@ -2794,10 +2794,9 @@
         if (mDebugRemoveAnimation) {
             Log.d(TAG, "generateRemove " + key
                     + "\nmIsExpanded " + mIsExpanded
-                    + "\nmAnimationsEnabled " + mAnimationsEnabled
-                    + "\n!invisible group " + !isChildInInvisibleGroup(child));
+                    + "\nmAnimationsEnabled " + mAnimationsEnabled);
         }
-        if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
+        if (mIsExpanded && mAnimationsEnabled) {
             if (!mChildrenToAddAnimated.contains(child)) {
                 if (mDebugRemoveAnimation) {
                     Log.d(TAG, "needsAnimation = true " + key);
@@ -2845,26 +2844,6 @@
         return hasAddEvent && mAddedHeadsUpChildren.contains(child);
     }
 
-    // TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in
-    //  ShadeListBuilder)
-    /**
-     * @param child the child to query
-     * @return whether a view is not a top level child but a child notification and that group is
-     * not expanded
-     */
-    @ShadeViewRefactor(RefactorComponent.ADAPTER)
-    private boolean isChildInInvisibleGroup(View child) {
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            NotificationEntry groupSummary =
-                    mGroupMembershipManager.getGroupSummary(row.getEntry());
-            if (groupSummary != null && groupSummary.getRow() != row) {
-                return row.getVisibility() == View.INVISIBLE;
-            }
-        }
-        return false;
-    }
-
     /**
      * Updates the scroll position when a child was removed
      *
@@ -5042,7 +5021,7 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setPanelFlinging(boolean flinging) {
-        mAmbientState.setIsFlinging(flinging);
+        mAmbientState.setFlinging(flinging);
         if (!flinging) {
             // re-calculate the stack height which was frozen while flinging
             updateStackPosition();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 353355b..eeed070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -163,7 +163,7 @@
                 // which is more expensive.
                 if (shelfState.hidden) {
                     // When the shelf is hidden, it won't clip views, so we don't hide rows
-                    return;
+                    continue;
                 }
 
                 final float shelfTop = shelfState.yTranslation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 87d1d66..4576a64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -23,7 +23,6 @@
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
 import android.os.Handler;
@@ -52,14 +51,11 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeController;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.VibratorHelper;
@@ -153,7 +149,6 @@
     private final Handler mHandler;
     private final KeyguardBypassController mKeyguardBypassController;
     private PowerManager.WakeLock mWakeLock;
-    private final com.android.systemui.shade.ShadeController mShadeController;
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final DozeParameters mDozeParameters;
     private final KeyguardStateController mKeyguardStateController;
@@ -167,7 +162,6 @@
     private KeyguardViewMediator mKeyguardViewMediator;
     private ScrimController mScrimController;
     private PendingAuthenticated mPendingAuthenticated = null;
-    private boolean mPendingShowBouncer;
     private boolean mHasScreenTurnedOnSinceAuthenticating;
     private boolean mFadedAwayAfterWakeAndUnlock;
     private BiometricModeListener mBiometricModeListener;
@@ -259,13 +253,11 @@
                 );
     }
 
-    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private final ScreenOffAnimationController mScreenOffAnimationController;
 
     @Inject
     public BiometricUnlockController(DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
-            ShadeController shadeController,
             NotificationShadeWindowController notificationShadeWindowController,
             KeyguardStateController keyguardStateController, Handler handler,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -278,13 +270,11 @@
             ScreenLifecycle screenLifecycle,
             AuthController authController,
             StatusBarStateController statusBarStateController,
-            KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             SessionTracker sessionTracker,
             LatencyTracker latencyTracker,
             ScreenOffAnimationController screenOffAnimationController,
             VibratorHelper vibrator) {
         mPowerManager = powerManager;
-        mShadeController = shadeController;
         mUpdateMonitor = keyguardUpdateMonitor;
         mDozeParameters = dozeParameters;
         mUpdateMonitor.registerCallback(this);
@@ -306,7 +296,6 @@
         mMetricsLogger = metricsLogger;
         mAuthController = authController;
         mStatusBarStateController = statusBarStateController;
-        mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
         mSessionTracker = sessionTracker;
         mScreenOffAnimationController = screenOffAnimationController;
         mVibratorHelper = vibrator;
@@ -462,22 +451,13 @@
                 break;
             case MODE_UNLOCK_COLLAPSING:
                 Trace.beginSection("MODE_UNLOCK_COLLAPSING");
-                if (!wasDeviceInteractive) {
-                    mPendingShowBouncer = true;
-                } else {
-                    mPendingShowBouncer = false;
-                    mKeyguardViewController.notifyKeyguardAuthenticated(
-                            false /* strongAuth */);
-                }
+                mKeyguardViewController.notifyKeyguardAuthenticated(
+                        false /* strongAuth */);
                 Trace.endSection();
                 break;
             case MODE_SHOW_BOUNCER:
                 Trace.beginSection("MODE_SHOW_BOUNCER");
-                if (!wasDeviceInteractive) {
-                    mPendingShowBouncer = true;
-                } else {
-                    showBouncer();
-                }
+                mKeyguardViewController.showBouncer(true);
                 Trace.endSection();
                 break;
             case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
@@ -515,15 +495,6 @@
         }
     }
 
-    private void showBouncer() {
-        if (mMode == MODE_SHOW_BOUNCER) {
-            mKeyguardViewController.showBouncer(true);
-        }
-        mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
-                false /* delayed */, BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
-        mPendingShowBouncer = false;
-    }
-
     public boolean hasPendingAuthentication() {
         return mPendingAuthenticated != null
                 && mUpdateMonitor
@@ -682,10 +653,7 @@
         final boolean fingerprintLockout = biometricSourceType == BiometricSourceType.FINGERPRINT
                 && (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
                 || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT);
-        final boolean faceLockout = biometricSourceType == BiometricSourceType.FACE
-                && (msgId == FaceManager.FACE_ERROR_LOCKOUT
-                || msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT);
-        if (fingerprintLockout || faceLockout) {
+        if (fingerprintLockout) {
             startWakeAndUnlock(MODE_SHOW_BOUNCER);
             UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN, getSessionId());
         }
@@ -742,13 +710,6 @@
     final WakefulnessLifecycle.Observer mWakefulnessObserver =
             new WakefulnessLifecycle.Observer() {
                 @Override
-                public void onFinishedWakingUp() {
-                    if (mPendingShowBouncer) {
-                        BiometricUnlockController.this.showBouncer();
-                    }
-                }
-
-                @Override
                 public void onStartedGoingToSleep() {
                     resetMode();
                     mFadedAwayAfterWakeAndUnlock = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 3259ae6..961b433 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -40,6 +40,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -220,6 +221,9 @@
 
     ViewGroup getBouncerContainer();
 
+    /** Get the Keyguard Message Area that displays auth messages. */
+    AuthKeyguardMessageArea getKeyguardMessageArea();
+
     int getStatusBarHeight();
 
     void updateQsExpansionEnabled();
@@ -390,8 +394,6 @@
     void fadeKeyguardAfterLaunchTransition(Runnable beforeFading,
             Runnable endRunnable, Runnable cancelRunnable);
 
-    void fadeKeyguardWhilePulsing();
-
     void animateKeyguardUnoccluding();
 
     void startLaunchTransitionTimeout();
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 7f2b6c3..1eafaf0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -99,11 +99,14 @@
 import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.DateTimeView;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
 
 import androidx.annotation.NonNull;
 import androidx.lifecycle.Lifecycle;
@@ -119,6 +122,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -508,10 +512,17 @@
     private CentralSurfacesComponent mCentralSurfacesComponent;
 
     // Flags for disabling the status bar
-    // Two variables becaseu the first one evidently ran out of room for new flags.
+    // Two variables because the first one evidently ran out of room for new flags.
     private int mDisabled1 = 0;
     private int mDisabled2 = 0;
 
+    /**
+     * This keeps track of whether we have (or haven't) registered the predictive back callback.
+     * Since we can have visible -> visible transitions, we need to avoid
+     * double-registering (or double-unregistering) our callback.
+     */
+    private boolean mIsBackCallbackRegistered = false;
+
     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
 
@@ -635,6 +646,12 @@
 
     private final InteractionJankMonitor mJankMonitor;
 
+    private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+        if (DEBUG) {
+            Log.d(TAG, "mOnBackInvokedCallback() called");
+        }
+        onBackPressed();
+    };
 
     /**
      * Public constructor for CentralSurfaces.
@@ -1565,6 +1582,11 @@
     }
 
     @Override
+    public AuthKeyguardMessageArea getKeyguardMessageArea() {
+        return mNotificationShadeWindowViewController.getKeyguardMessageArea();
+    }
+
+    @Override
     public int getStatusBarHeight() {
         return mStatusBarWindowController.getStatusBarHeight();
     }
@@ -1697,13 +1719,18 @@
                 }
 
                 @Override
-                public void onLaunchAnimationCancelled() {
+                public void onLaunchAnimationCancelled(@Nullable Boolean newKeyguardOccludedState) {
+                    if (newKeyguardOccludedState != null) {
+                        mKeyguardViewMediator.setOccluded(
+                                newKeyguardOccludedState, false /* animate */);
+                    }
+
                     // Set mIsLaunchingActivityOverLockscreen to false before actually finishing the
                     // animation so that we can assume that mIsLaunchingActivityOverLockscreen
                     // being true means that we will collapse the shade (or at least run the
                     // post collapse runnables) later on.
                     CentralSurfacesImpl.this.mIsLaunchingActivityOverLockscreen = false;
-                    getDelegate().onLaunchAnimationCancelled();
+                    getDelegate().onLaunchAnimationCancelled(newKeyguardOccludedState);
                 }
             };
         } else if (dismissShade) {
@@ -2725,9 +2752,38 @@
         if (visibleToUser) {
             handleVisibleToUserChangedImpl(visibleToUser);
             mNotificationLogger.startNotificationLogging();
+
+            if (!mIsBackCallbackRegistered) {
+                ViewRootImpl viewRootImpl = getViewRootImpl();
+                if (viewRootImpl != null) {
+                    viewRootImpl.getOnBackInvokedDispatcher()
+                            .registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+                                    mOnBackInvokedCallback);
+                    mIsBackCallbackRegistered = true;
+                    if (DEBUG) Log.d(TAG, "is now VISIBLE to user AND callback registered");
+                }
+            } else {
+                if (DEBUG) Log.d(TAG, "is now VISIBLE to user, BUT callback ALREADY unregistered");
+            }
         } else {
             mNotificationLogger.stopNotificationLogging();
             handleVisibleToUserChangedImpl(visibleToUser);
+
+            if (mIsBackCallbackRegistered) {
+                ViewRootImpl viewRootImpl = getViewRootImpl();
+                if (viewRootImpl != null) {
+                    viewRootImpl.getOnBackInvokedDispatcher()
+                            .unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+                    mIsBackCallbackRegistered = false;
+                    if (DEBUG) Log.d(TAG, "is NOT VISIBLE to user, AND callback unregistered");
+                }
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG,
+                            "is NOT VISIBLE to user, BUT NO callback (or callback ALREADY "
+                                    + "unregistered)");
+                }
+            }
         }
     }
 
@@ -2999,19 +3055,6 @@
     }
 
     /**
-     * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
-     * fading.
-     */
-    @Override
-    public void fadeKeyguardWhilePulsing() {
-        mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
-                ()-> {
-                hideKeyguard();
-                mStatusBarKeyguardViewManager.onKeyguardFadedAway();
-            }).start();
-    }
-
-    /**
      * Plays the animation when an activity that was occluding Keyguard goes away.
      */
     @Override
@@ -3300,14 +3343,12 @@
         // show the bouncer/lockscreen.
         if (!mKeyguardViewMediator.isHiding()
                 && !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
-            if (mState == StatusBarState.SHADE_LOCKED
-                    && mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
+            if (mState == StatusBarState.SHADE_LOCKED) {
                 // shade is showing while locked on the keyguard, so go back to showing the
                 // lock screen where users can use the UDFPS affordance to enter the device
                 mStatusBarKeyguardViewManager.reset(true);
-            } else if ((mState == StatusBarState.KEYGUARD
-                    && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing())
-                    || mState == StatusBarState.SHADE_LOCKED) {
+            } else if (mState == StatusBarState.KEYGUARD
+                    && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()) {
                 mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */);
             }
         }
@@ -3453,6 +3494,12 @@
         return mNotificationPanelViewController.getKeyguardBottomAreaView();
     }
 
+    protected ViewRootImpl getViewRootImpl()  {
+        NotificationShadeWindowView nswv = getNotificationShadeWindowView();
+        if (nswv != null) return nswv.getViewRootImpl();
+
+        return null;
+    }
     /**
      * Propagation of the bouncer state, indicating that it's fully visible.
      */
@@ -3561,6 +3608,7 @@
             dismissVolumeDialog();
             mWakeUpCoordinator.setFullyAwake(false);
             mKeyguardBypassController.onStartedGoingToSleep();
+            mStatusBarTouchableRegionManager.updateTouchableRegion();
 
             // The unlocked screen off and fold to aod animations might use our LightRevealScrim -
             // we need to be expanded for it to be visible.
@@ -3589,6 +3637,7 @@
                 // once we fully woke up.
                 updateRevealEffect(true /* wakingUp */);
                 updateNotificationPanelTouchState();
+                mStatusBarTouchableRegionManager.updateTouchableRegion();
 
                 // If we are waking up during the screen off animation, we should undo making the
                 // expanded visible (we did that so the LightRevealScrim would be visible).
@@ -3770,6 +3819,12 @@
         updateScrimController();
     }
 
+    @VisibleForTesting
+    public void setNotificationShadeWindowViewController(
+            NotificationShadeWindowViewController nswvc) {
+        mNotificationShadeWindowViewController = nswvc;
+    }
+
     /**
      * Set the amount of progress we are currently in if we're transitioning to the full shade.
      * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index ddff7d8..24ce5e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -28,8 +28,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 
-import androidx.annotation.Nullable;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.assist.AssistManager;
@@ -50,11 +48,9 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.Assert;
 
 import java.util.ArrayList;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -80,8 +76,6 @@
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
-    @Nullable
-    private final FoldAodAnimationController mFoldAodAnimationController;
     private final HeadsUpManagerPhone mHeadsUpManagerPhone;
     private final BatteryController mBatteryController;
     private final ScrimController mScrimController;
@@ -114,7 +108,6 @@
             Lazy<AssistManager> assistManagerLazy,
             DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
             PulseExpansionHandler pulseExpansionHandler,
-            Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
             NotificationShadeWindowController notificationShadeWindowController,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             AuthController authController,
@@ -138,8 +131,6 @@
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
         mAuthController = authController;
         mNotificationIconAreaController = notificationIconAreaController;
-        mFoldAodAnimationController = sysUIUnfoldComponent
-                .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
     }
 
     // TODO: we should try to not pass status bar in here if we can avoid it.
@@ -167,6 +158,7 @@
     }
 
     void firePowerSaveChanged(boolean active) {
+        Assert.isMainThread();
         for (Callback callback : mCallbacks) {
             callback.onPowerSaveChanged(active);
         }
@@ -177,6 +169,7 @@
             entry.setPulseSuppressed(true);
             mNotificationIconAreaController.updateAodNotificationIcons();
         };
+        Assert.isMainThread();
         for (Callback callback : mCallbacks) {
             callback.onNotificationAlerted(pulseSuppressedListener);
         }
@@ -193,11 +186,13 @@
 
     @Override
     public void addCallback(@NonNull Callback callback) {
+        Assert.isMainThread();
         mCallbacks.add(callback);
     }
 
     @Override
     public void removeCallback(@NonNull Callback callback) {
+        Assert.isMainThread();
         mCallbacks.remove(callback);
     }
 
@@ -212,12 +207,10 @@
     }
 
     void updateDozing() {
-        // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
-        boolean
-                dozing =
-                mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
-                        || mBiometricUnlockControllerLazy.get().getMode()
-                        == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+        Assert.isMainThread();
+
+        boolean dozing =
+                mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
         // When in wake-and-unlock we may not have received a change to StatusBarState
         // but we still should not be dozing, manually set to false.
         if (mBiometricUnlockControllerLazy.get().getMode()
@@ -225,10 +218,10 @@
             dozing = false;
         }
 
-        mStatusBarStateController.setIsDozing(dozing);
-        if (mFoldAodAnimationController != null) {
-            mFoldAodAnimationController.setIsDozing(dozing);
+        for (Callback callback : mCallbacks) {
+            callback.onDozingChanged(dozing);
         }
+        mStatusBarStateController.setIsDozing(dozing);
     }
 
     @Override
@@ -452,6 +445,7 @@
             return;
         }
         mAlwaysOnSuppressed = suppressed;
+        Assert.isMainThread();
         for (Callback callback : mCallbacks) {
             callback.onAlwaysOnSuppressedChanged(suppressed);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 6bfb0da..90d0b69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -115,9 +115,7 @@
                     mInitialTouchY = y;
                     int startHeight = (int) (mPickedChild.getActualHeight()
                                                 + mPickedChild.getTranslationY());
-                    float maxPanelHeight = mPanel.getMaxPanelHeight();
-                    mPanel.setPanelScrimMinFraction(maxPanelHeight > 0f
-                            ? (float) startHeight / maxPanelHeight : 0f);
+                    mPanel.setHeadsUpDraggingStartingHeight(startHeight);
                     mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight);
                     // This call needs to be after the expansion start otherwise we will get a
                     // flicker of one frame as it's not expanded yet.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
deleted file mode 100644
index cc451d9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
-
-import android.app.ActivityTaskManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsResponse;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
-import android.view.WindowInsets;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.controls.dagger.ControlsComponent;
-import com.android.systemui.controls.management.ControlsListingController;
-import com.android.systemui.controls.ui.ControlsActivity;
-import com.android.systemui.controls.ui.ControlsUiController;
-import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
- * text.
- */
-public class KeyguardBottomAreaView extends FrameLayout {
-
-    private static final String TAG = "CentralSurfaces/KeyguardBottomAreaView";
-    private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
-
-    private ImageView mWalletButton;
-    private ImageView mQRCodeScannerButton;
-    private ImageView mControlsButton;
-    private boolean mHasCard = false;
-    private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
-    private QuickAccessWalletController mQuickAccessWalletController;
-    private QRCodeScannerController mQRCodeScannerController;
-    private ControlsComponent mControlsComponent;
-    private boolean mControlServicesAvailable = false;
-
-    @Nullable private View mAmbientIndicationArea;
-    private ViewGroup mIndicationArea;
-    private TextView mIndicationText;
-    private TextView mIndicationTextBottom;
-    private ViewGroup mOverlayContainer;
-
-    private ActivityStarter mActivityStarter;
-    private KeyguardStateController mKeyguardStateController;
-    private FalsingManager mFalsingManager;
-
-    private boolean mDozing;
-    private int mIndicationBottomMargin;
-    private int mIndicationPadding;
-    private float mDarkAmount;
-    private int mBurnInXOffset;
-    private int mBurnInYOffset;
-
-    private final ControlsListingController.ControlsListingCallback mListingCallback =
-            serviceInfos -> post(() -> {
-                boolean available = !serviceInfos.isEmpty();
-
-                if (available != mControlServicesAvailable) {
-                    mControlServicesAvailable = available;
-                    updateControlsVisibility();
-                    updateAffordanceColors();
-                }
-            });
-
-    private final KeyguardStateController.Callback mKeyguardStateCallback =
-            new KeyguardStateController.Callback() {
-        @Override
-        public void onKeyguardShowingChanged() {
-            if (mKeyguardStateController.isShowing()) {
-                if (mQuickAccessWalletController != null) {
-                    mQuickAccessWalletController.queryWalletCards(mCardRetriever);
-                }
-            }
-        }
-    };
-
-    @Nullable private KeyguardBottomAreaViewBinder.Binding mBinding;
-    private boolean mUsesBinder;
-
-    public KeyguardBottomAreaView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    /**
-     * Initializes the view.
-     */
-    public void init(
-            final KeyguardBottomAreaViewModel viewModel,
-            final FalsingManager falsingManager) {
-        Log.i(TAG, System.identityHashCode(this) + " initialized with a binder");
-        mUsesBinder = true;
-        mBinding = KeyguardBottomAreaViewBinder.bind(this, viewModel, falsingManager);
-    }
-
-    /**
-     * Initializes the {@link KeyguardBottomAreaView} with the given dependencies
-     *
-     * @deprecated Use
-     * {@link #init(KeyguardBottomAreaViewModel, FalsingManager)} instead
-     */
-    @Deprecated
-    public void init(
-            FalsingManager falsingManager,
-            QuickAccessWalletController controller,
-            ControlsComponent controlsComponent,
-            QRCodeScannerController qrCodeScannerController) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        Log.i(TAG, "initialized without a binder");
-        mFalsingManager = falsingManager;
-
-        mQuickAccessWalletController = controller;
-        mQuickAccessWalletController.setupWalletChangeObservers(
-                mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
-        mQuickAccessWalletController.updateWalletPreference();
-        mQuickAccessWalletController.queryWalletCards(mCardRetriever);
-        updateWalletVisibility();
-
-        mControlsComponent = controlsComponent;
-        mControlsComponent.getControlsListingController().ifPresent(
-                c -> c.addCallback(mListingCallback));
-
-        mQRCodeScannerController = qrCodeScannerController;
-        mQRCodeScannerController.registerQRCodeScannerChangeObservers(
-                QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
-                QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
-        updateQRCodeButtonVisibility();
-
-        updateAffordanceColors();
-    }
-
-    /**
-     * Initializes this instance of {@link KeyguardBottomAreaView} based on the given instance of
-     * another {@link KeyguardBottomAreaView}
-     */
-    public void initFrom(KeyguardBottomAreaView oldBottomArea) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        // if it exists, continue to use the original ambient indication container
-        // instead of the newly inflated one
-        if (mAmbientIndicationArea != null) {
-            // remove old ambient indication from its parent
-            View originalAmbientIndicationView =
-                    oldBottomArea.findViewById(R.id.ambient_indication_container);
-            ((ViewGroup) originalAmbientIndicationView.getParent())
-                    .removeView(originalAmbientIndicationView);
-
-            // remove current ambient indication from its parent (discard)
-            ViewGroup ambientIndicationParent = (ViewGroup) mAmbientIndicationArea.getParent();
-            int ambientIndicationIndex =
-                    ambientIndicationParent.indexOfChild(mAmbientIndicationArea);
-            ambientIndicationParent.removeView(mAmbientIndicationArea);
-
-            // add the old ambient indication to this view
-            ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex);
-            mAmbientIndicationArea = originalAmbientIndicationView;
-
-            // update burn-in offsets
-            dozeTimeTick();
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        if (mUsesBinder) {
-            return;
-        }
-
-        mOverlayContainer = findViewById(R.id.overlay_container);
-        mWalletButton = findViewById(R.id.wallet_button);
-        mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button);
-        mControlsButton = findViewById(R.id.controls_button);
-        mIndicationArea = findViewById(R.id.keyguard_indication_area);
-        mAmbientIndicationArea = findViewById(R.id.ambient_indication_container);
-        mIndicationText = findViewById(R.id.keyguard_indication_text);
-        mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
-        mIndicationBottomMargin = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_margin_bottom);
-        mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
-        mKeyguardStateController = Dependency.get(KeyguardStateController.class);
-        mKeyguardStateController.addCallback(mKeyguardStateCallback);
-        setClipChildren(false);
-        setClipToPadding(false);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
-
-        mIndicationPadding = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_area_padding);
-        updateWalletVisibility();
-        updateQRCodeButtonVisibility();
-        updateControlsVisibility();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mUsesBinder) {
-            return;
-        }
-
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-        mKeyguardStateController.addCallback(mKeyguardStateCallback);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mUsesBinder) {
-            return;
-        }
-
-        mKeyguardStateController.removeCallback(mKeyguardStateCallback);
-
-        if (mQuickAccessWalletController != null) {
-            mQuickAccessWalletController.unregisterWalletChangeObservers(
-                    WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
-        }
-
-        if (mQRCodeScannerController != null) {
-            mQRCodeScannerController.unregisterQRCodeScannerChangeObservers(
-                    QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
-                    QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
-        }
-
-        if (mControlsComponent != null) {
-            mControlsComponent.getControlsListingController().ifPresent(
-                    c -> c.removeCallback(mListingCallback));
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (mUsesBinder) {
-            if (mBinding != null) {
-                mBinding.onConfigurationChanged();
-            }
-            return;
-        }
-
-        mIndicationBottomMargin = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_margin_bottom);
-        mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
-        MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
-        if (mlp.bottomMargin != mIndicationBottomMargin) {
-            mlp.bottomMargin = mIndicationBottomMargin;
-            mIndicationArea.setLayoutParams(mlp);
-        }
-
-        // Respect font size setting.
-        mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.text_size_small_material));
-        mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.text_size_small_material));
-
-        ViewGroup.LayoutParams lp = mWalletButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
-        mWalletButton.setLayoutParams(lp);
-
-        lp = mQRCodeScannerButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
-        mQRCodeScannerButton.setLayoutParams(lp);
-
-        lp = mControlsButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
-        mControlsButton.setLayoutParams(lp);
-
-        mIndicationPadding = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_area_padding);
-
-        updateWalletVisibility();
-        updateQRCodeButtonVisibility();
-        updateAffordanceColors();
-    }
-
-    private void updateWalletVisibility() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mDozing
-                || mQuickAccessWalletController == null
-                || !mQuickAccessWalletController.isWalletEnabled()
-                || !mHasCard) {
-            mWalletButton.setVisibility(GONE);
-
-            if (mControlsButton.getVisibility() == GONE) {
-                mIndicationArea.setPadding(0, 0, 0, 0);
-            }
-        } else {
-            mWalletButton.setVisibility(VISIBLE);
-            mWalletButton.setOnClickListener(this::onWalletClick);
-            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
-        }
-    }
-
-    private void updateControlsVisibility() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mControlsComponent == null) return;
-
-        mControlsButton.setImageResource(mControlsComponent.getTileImageId());
-        mControlsButton.setContentDescription(getContext()
-                .getString(mControlsComponent.getTileTitleId()));
-        updateAffordanceColors();
-
-        boolean hasFavorites = mControlsComponent.getControlsController()
-                .map(c -> c.getFavorites().size() > 0)
-                .orElse(false);
-        if (mDozing
-                || !hasFavorites
-                || !mControlServicesAvailable
-                || mControlsComponent.getVisibility() != AVAILABLE) {
-            mControlsButton.setVisibility(GONE);
-            if (mWalletButton.getVisibility() == GONE) {
-                mIndicationArea.setPadding(0, 0, 0, 0);
-            }
-        } else {
-            mControlsButton.setVisibility(VISIBLE);
-            mControlsButton.setOnClickListener(this::onControlsClick);
-            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
-        }
-    }
-
-    public void setDarkAmount(float darkAmount) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (darkAmount == mDarkAmount) {
-            return;
-        }
-        mDarkAmount = darkAmount;
-        dozeTimeTick();
-    }
-
-    /**
-     * Returns a list of animators to use to animate the indication areas.
-     */
-    public List<ViewPropertyAnimator> getIndicationAreaAnimators() {
-        if (mUsesBinder) {
-            return checkNotNull(mBinding).getIndicationAreaAnimators();
-        }
-
-        List<ViewPropertyAnimator> animators =
-                new ArrayList<>(mAmbientIndicationArea != null ? 2 : 1);
-        animators.add(mIndicationArea.animate());
-        if (mAmbientIndicationArea != null) {
-            animators.add(mAmbientIndicationArea.animate());
-        }
-        return animators;
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    private void startFinishDozeAnimation() {
-        long delay = 0;
-        if (mWalletButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mWalletButton, delay);
-        }
-        if (mQRCodeScannerButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mQRCodeScannerButton, delay);
-        }
-        if (mControlsButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mControlsButton, delay);
-        }
-    }
-
-    private void startFinishDozeAnimationElement(View element, long delay) {
-        element.setAlpha(0f);
-        element.setTranslationY(element.getHeight() / 2);
-        element.animate()
-                .alpha(1f)
-                .translationY(0f)
-                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
-                .setStartDelay(delay)
-                .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
-    }
-
-    public void setDozing(boolean dozing, boolean animate) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        mDozing = dozing;
-
-        updateWalletVisibility();
-        updateControlsVisibility();
-        updateQRCodeButtonVisibility();
-
-        if (dozing) {
-            mOverlayContainer.setVisibility(INVISIBLE);
-        } else {
-            mOverlayContainer.setVisibility(VISIBLE);
-            if (animate) {
-                startFinishDozeAnimation();
-            }
-        }
-    }
-
-    public void dozeTimeTick() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
-                - mBurnInYOffset;
-        mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
-        if (mAmbientIndicationArea != null) {
-            mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
-        }
-    }
-
-    public void setAntiBurnInOffsetX(int burnInXOffset) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mBurnInXOffset == burnInXOffset) {
-            return;
-        }
-        mBurnInXOffset = burnInXOffset;
-        mIndicationArea.setTranslationX(burnInXOffset);
-        if (mAmbientIndicationArea != null) {
-            mAmbientIndicationArea.setTranslationX(burnInXOffset);
-        }
-    }
-
-    /**
-     * Sets the alpha of various sub-components, for example the indication areas and bottom quick
-     * action buttons. Does not set the alpha of the lock icon.
-     */
-    public void setComponentAlphas(float alpha) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        setImportantForAccessibility(
-                alpha == 0f
-                        ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
-                        : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
-        if (mAmbientIndicationArea != null) {
-            mAmbientIndicationArea.setAlpha(alpha);
-        }
-        mIndicationArea.setAlpha(alpha);
-        mWalletButton.setAlpha(alpha);
-        mQRCodeScannerButton.setAlpha(alpha);
-        mControlsButton.setAlpha(alpha);
-    }
-
-    @Override
-    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        int bottom = insets.getDisplayCutout() != null
-                ? insets.getDisplayCutout().getSafeInsetBottom() : 0;
-        if (isPaddingRelative()) {
-            setPaddingRelative(getPaddingStart(), getPaddingTop(), getPaddingEnd(), bottom);
-        } else {
-            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottom);
-        }
-        return insets;
-    }
-
-    private void updateQRCodeButtonVisibility() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mQuickAccessWalletController != null
-                && mQuickAccessWalletController.isWalletEnabled()) {
-            // Don't enable if quick access wallet is enabled
-            return;
-        }
-
-        if (mQRCodeScannerController != null
-                && mQRCodeScannerController.isEnabledForLockScreenButton()) {
-            mQRCodeScannerButton.setVisibility(VISIBLE);
-            mQRCodeScannerButton.setOnClickListener(this::onQRCodeScannerClicked);
-            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
-        } else {
-            mQRCodeScannerButton.setVisibility(GONE);
-            if (mControlsButton.getVisibility() == GONE) {
-                mIndicationArea.setPadding(0, 0, 0, 0);
-            }
-        }
-    }
-
-    private void onQRCodeScannerClicked(View view) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        Intent intent = mQRCodeScannerController.getIntent();
-        if (intent != null) {
-            try {
-                ActivityTaskManager.getService().startActivityAsUser(
-                                null, getContext().getBasePackageName(),
-                                getContext().getAttributionTag(), intent,
-                                intent.resolveTypeIfNeeded(getContext().getContentResolver()),
-                                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
-                                UserHandle.CURRENT.getIdentifier());
-            } catch (RemoteException e) {
-                // This is unexpected. Nonetheless, just log the error and prevent the UI from
-                // crashing
-                Log.e(TAG, "Unexpected intent: " + intent
-                        + " when the QR code scanner button was clicked");
-            }
-        }
-    }
-
-    private void updateAffordanceColors() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        int iconColor = Utils.getColorAttrDefaultColor(
-                mContext,
-                com.android.internal.R.attr.textColorPrimary);
-        mWalletButton.getDrawable().setTint(iconColor);
-        mControlsButton.getDrawable().setTint(iconColor);
-        mQRCodeScannerButton.getDrawable().setTint(iconColor);
-
-        ColorStateList bgColor = Utils.getColorAttr(
-                mContext,
-                com.android.internal.R.attr.colorSurface);
-        mWalletButton.setBackgroundTintList(bgColor);
-        mControlsButton.setBackgroundTintList(bgColor);
-        mQRCodeScannerButton.setBackgroundTintList(bgColor);
-    }
-
-    private void onWalletClick(View v) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        // More coming here; need to inform the user about how to proceed
-        if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return;
-        }
-
-        ActivityLaunchAnimator.Controller animationController = createLaunchAnimationController(v);
-        mQuickAccessWalletController.startQuickAccessUiIntent(
-                mActivityStarter, animationController, mHasCard);
-    }
-
-    protected ActivityLaunchAnimator.Controller createLaunchAnimationController(View view) {
-        return ActivityLaunchAnimator.Controller.fromView(view, null);
-    }
-
-    private void onControlsClick(View v) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return;
-        }
-
-        Intent intent = new Intent(mContext, ControlsActivity.class)
-                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
-                .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
-
-        ActivityLaunchAnimator.Controller controller =
-                v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */)
-                        : null;
-        if (mControlsComponent.getVisibility() == AVAILABLE) {
-            mActivityStarter.startActivity(intent, true /* dismissShade */, controller,
-                    true /* showOverLockscreenWhenLocked */);
-        } else {
-            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller);
-        }
-    }
-
-    private class WalletCardRetriever implements
-            QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
-
-        @Override
-        public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
-            mHasCard = !response.getWalletCards().isEmpty();
-            Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
-            post(() -> {
-                if (tileIcon != null) {
-                    mWalletButton.setImageDrawable(tileIcon);
-                }
-                updateWalletVisibility();
-                updateAffordanceColors();
-            });
-        }
-
-        @Override
-        public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
-            mHasCard = false;
-            post(() -> {
-                updateWalletVisibility();
-                updateAffordanceColors();
-            });
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
new file mode 100644
index 0000000..4897c52
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.plugins.FalsingManager
+
+/**
+ * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
+ * elements. A secondary concern is the interaction of the quick affordance elements with the
+ * indication area between them, though the indication area is primarily controlled elsewhere.
+ */
+class KeyguardBottomAreaView
+@JvmOverloads
+constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0,
+) :
+    FrameLayout(
+        context,
+        attrs,
+        defStyleAttr,
+        defStyleRes,
+    ) {
+
+    private var ambientIndicationArea: View? = null
+    private lateinit var binding: KeyguardBottomAreaViewBinder.Binding
+
+    /** Initializes the view. */
+    fun init(
+        viewModel: KeyguardBottomAreaViewModel,
+        falsingManager: FalsingManager,
+    ) {
+        binding = bind(this, viewModel, falsingManager)
+    }
+
+    /**
+     * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
+     * [KeyguardBottomAreaView]
+     */
+    fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
+        // if it exists, continue to use the original ambient indication container
+        // instead of the newly inflated one
+        ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
+            // remove old ambient indication from its parent
+            val originalAmbientIndicationView =
+                oldBottomArea.findViewById<View>(R.id.ambient_indication_container)
+            (originalAmbientIndicationView.parent as ViewGroup).removeView(
+                originalAmbientIndicationView
+            )
+
+            // remove current ambient indication from its parent (discard)
+            val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
+            val ambientIndicationIndex =
+                ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
+            ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
+
+            // add the old ambient indication to this view
+            ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
+            ambientIndicationArea = originalAmbientIndicationView
+        }
+    }
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        ambientIndicationArea = findViewById(R.id.ambient_indication_container)
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        binding.onConfigurationChanged()
+    }
+
+    /** Returns a list of animators to use to animate the indication areas. */
+    val indicationAreaAnimators: List<ViewPropertyAnimator>
+        get() = binding.getIndicationAreaAnimators()
+
+    override fun hasOverlappingRendering(): Boolean {
+        return false
+    }
+
+    override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
+        val bottom = insets.displayCutout?.safeInsetBottom ?: 0
+        if (isPaddingRelative) {
+            setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
+        } else {
+            setPadding(paddingLeft, paddingTop, paddingRight, bottom)
+        }
+        return insets
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index e63c383..44aef7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -220,6 +220,7 @@
                     && !mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
                             KeyguardUpdateMonitor.getCurrentUser())
                     && !needsFullscreenBouncer()
+                    && !mKeyguardUpdateMonitor.isFaceLockedOut()
                     && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
                     && !mKeyguardBypassController.getBypassEnabled()) {
                 mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cb0a148..4d1c361 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -259,11 +259,17 @@
     private boolean mKeyguardOccluded;
 
     @Inject
-    public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
-            AlarmManager alarmManager, KeyguardStateController keyguardStateController,
-            DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
-            KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
-            ConfigurationController configurationController, @Main Executor mainExecutor,
+    public ScrimController(
+            LightBarController lightBarController,
+            DozeParameters dozeParameters,
+            AlarmManager alarmManager,
+            KeyguardStateController keyguardStateController,
+            DelayedWakeLock.Builder delayedWakeLockBuilder,
+            Handler handler,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DockManager dockManager,
+            ConfigurationController configurationController,
+            @Main Executor mainExecutor,
             ScreenOffAnimationController screenOffAnimationController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
@@ -826,20 +832,15 @@
                 mBehindTint = Color.BLACK;
             } else {
                 mBehindAlpha = behindAlpha;
-                if (mState == ScrimState.SHADE_LOCKED) {
+                if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+                    mNotificationsAlpha = MathUtils
+                            .saturate(mTransitionToLockScreenFullShadeNotificationsProgress);
+                } else if (mState == ScrimState.SHADE_LOCKED) {
                     // going from KEYGUARD to SHADE_LOCKED state
                     mNotificationsAlpha = getInterpolatedFraction();
                 } else {
                     mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
                 }
-                if (mState == ScrimState.KEYGUARD
-                        && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
-                    // Interpolate the notification alpha when transitioning!
-                    mNotificationsAlpha = MathUtils.lerp(
-                            mNotificationsAlpha,
-                            getInterpolatedFraction(),
-                            mTransitionToLockScreenFullShadeNotificationsProgress);
-                }
                 mNotificationsTint = mState.getNotifTint();
                 mBehindTint = behindTint;
             }
@@ -1430,6 +1431,8 @@
         pw.print(mNotificationsAlpha);
         pw.print(" tint=0x");
         pw.println(Integer.toHexString(mNotificationsScrim.getTint()));
+        pw.print(" expansionProgress=");
+        pw.println(mTransitionToLockScreenFullShadeNotificationsProgress);
 
         pw.print("  mTracking=");
         pw.println(mTracking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 0dd1f44..985f3cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -44,7 +44,7 @@
 
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardMessageArea;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.KeyguardMessageAreaController;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -122,7 +122,7 @@
     private final DreamOverlayStateController mDreamOverlayStateController;
     @Nullable
     private final FoldAodAnimationController mFoldAodAnimationController;
-    private KeyguardMessageAreaController mKeyguardMessageAreaController;
+    private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
     private final Lazy<com.android.systemui.shade.ShadeController> mShadeController;
 
     private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@@ -311,7 +311,7 @@
         mBypassController = bypassController;
         mNotificationContainer = notificationContainer;
         mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create(
-            KeyguardMessageArea.findSecurityMessageDisplay(container));
+                centralSurfaces.getKeyguardMessageArea());
 
         registerListeners();
     }
@@ -378,11 +378,9 @@
             return;
         } else if (mNotificationPanelViewController.isUnlockHintRunning()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
-        } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
-                && mKeyguardUpdateManager.isUdfpsEnrolled()) {
+        } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
             // Don't expand to the bouncer. Instead transition back to the lock screen (see
-            // CentralSurfaces#showBouncerOrLockScreenIfKeyguard) where the user can use the UDFPS
-            // affordance to enter the device (or swipe up to the input bouncer)
+            // CentralSurfaces#showBouncerOrLockScreenIfKeyguard)
             return;
         } else if (bouncerNeedsScrimming()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
@@ -616,7 +614,8 @@
     private void updateAlternateAuthShowing(boolean updateScrim) {
         final boolean isShowingAltAuth = isShowingAlternateAuth();
         if (mKeyguardMessageAreaController != null) {
-            mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAltAuth);
+            mKeyguardMessageAreaController.setIsVisible(isShowingAltAuth);
+            mKeyguardMessageAreaController.setMessage("");
         }
         mBypassController.setAltBouncerShowing(isShowingAltAuth);
         mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAltAuth);
@@ -837,30 +836,24 @@
             });
         } else {
             executeAfterKeyguardGoneAction();
-            boolean wakeUnlockPulsing =
-                    mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
             mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
             mBiometricUnlockController.startKeyguardFadingAway();
             hideBouncer(true /* destroyView */);
-            if (wakeUnlockPulsing) {
-                mCentralSurfaces.fadeKeyguardWhilePulsing();
+
+            boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
+            if (!staying) {
+                mNotificationShadeWindowController.setKeyguardFadingAway(true);
                 wakeAndUnlockDejank();
+                mCentralSurfaces.hideKeyguard();
+                // hide() will happen asynchronously and might arrive after the scrims
+                // were already hidden, this means that the transition callback won't
+                // be triggered anymore and StatusBarWindowController will be forever in
+                // the fadingAway state.
+                mCentralSurfaces.updateScrimController();
             } else {
-                boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
-                if (!staying) {
-                    mNotificationShadeWindowController.setKeyguardFadingAway(true);
-                    wakeAndUnlockDejank();
-                    mCentralSurfaces.hideKeyguard();
-                    // hide() will happen asynchronously and might arrive after the scrims
-                    // were already hidden, this means that the transition callback won't
-                    // be triggered anymore and StatusBarWindowController will be forever in
-                    // the fadingAway state.
-                    mCentralSurfaces.updateScrimController();
-                } else {
-                    mCentralSurfaces.hideKeyguard();
-                    mCentralSurfaces.finishKeyguardFadingAway();
-                    mBiometricUnlockController.finishKeyguardFadingAway();
-                }
+                mCentralSurfaces.hideKeyguard();
+                mCentralSurfaces.finishKeyguardFadingAway();
+                mBiometricUnlockController.finishKeyguardFadingAway();
             }
 
             updateStates();
@@ -1042,7 +1035,6 @@
         if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
             mNotificationShadeWindowController.setBouncerShowing(bouncerShowing);
             mCentralSurfaces.setBouncerShowing(bouncerShowing);
-            mKeyguardMessageAreaController.setBouncerShowing(bouncerShowing);
         }
 
         if (occluded != mLastOccluded || mFirstUpdate) {
@@ -1191,7 +1183,8 @@
         }
     }
 
-    public void showBouncerMessage(String message, ColorStateList colorState) {
+    /** Display security message to relevant KeyguardMessageArea. */
+    public void setKeyguardMessage(String message, ColorStateList colorState) {
         if (isShowingAlternateAuth()) {
             if (mKeyguardMessageAreaController != null) {
                 mKeyguardMessageAreaController.setMessage(message);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
index c092216..ee948c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
@@ -51,7 +51,7 @@
         centralSurfaces.notificationPanelViewController.applyLaunchAnimationProgress(linearProgress)
     }
 
-    override fun onLaunchAnimationCancelled() {
+    override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
         delegate.onLaunchAnimationCancelled()
         centralSurfaces.notificationPanelViewController.setIsLaunchAnimationRunning(false)
         centralSurfaces.onLaunchAnimationCancelled(isLaunchForActivity)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 75dac1a..d9c0293 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -55,6 +55,7 @@
     private final Context mContext;
     private final HeadsUpManagerPhone mHeadsUpManager;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
+    private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
 
     private boolean mIsStatusBarExpanded = false;
     private boolean mShouldAdjustInsets = false;
@@ -72,7 +73,8 @@
             Context context,
             NotificationShadeWindowController notificationShadeWindowController,
             ConfigurationController configurationController,
-            HeadsUpManagerPhone headsUpManager
+            HeadsUpManagerPhone headsUpManager,
+            UnlockedScreenOffAnimationController unlockedScreenOffAnimationController
     ) {
         mContext = context;
         initResources();
@@ -115,6 +117,8 @@
         mNotificationShadeWindowController.setForcePluginOpenListener((forceOpen) -> {
             updateTouchableRegion();
         });
+
+        mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
     }
 
     protected void setup(
@@ -179,7 +183,7 @@
     /**
      * Set the touchable portion of the status bar based on what elements are visible.
      */
-    private void updateTouchableRegion() {
+    public void updateTouchableRegion() {
         boolean hasCutoutInset = (mNotificationShadeWindowView != null)
                 && (mNotificationShadeWindowView.getRootWindowInsets() != null)
                 && (mNotificationShadeWindowView.getRootWindowInsets().getDisplayCutout() != null);
@@ -242,12 +246,25 @@
         touchableRegion.union(bounds);
     }
 
+    /**
+     * Helper to let us know when calculating the region is not needed because we know the entire
+     * screen needs to be touchable.
+     */
+    private boolean shouldMakeEntireScreenTouchable() {
+        // The touchable region is always the full area when expanded, whether we're showing the
+        // shade or the bouncer. It's also fully touchable when the screen off animation is playing
+        // since we don't want stray touches to go through the light reveal scrim to whatever is
+        // underneath.
+        return mIsStatusBarExpanded
+                || mCentralSurfaces.isBouncerShowing()
+                || mUnlockedScreenOffAnimationController.isAnimationPlaying();
+    }
+
     private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener =
             new OnComputeInternalInsetsListener() {
         @Override
         public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-            if (mIsStatusBarExpanded || mCentralSurfaces.isBouncerShowing()) {
-                // The touchable region is always the full area when expanded
+            if (shouldMakeEntireScreenTouchable()) {
                 return;
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
index a6160aa..6b7c42e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
@@ -114,8 +114,8 @@
                     "end state=${state.panelStateToString()} " +
                     "f=$fraction " +
                     "expanded=$expanded " +
-                    "tracking=$tracking" +
-                    "drawDownPxAmount=$dragDownPxAmount " +
+                    "tracking=$tracking " +
+                    "dragDownPxAmount=$dragDownPxAmount " +
                     "${if (fullyOpened) " fullyOpened" else ""} " +
                     if (fullyClosed) " fullyClosed" else ""
         )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 88eccb5..681dc6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -18,6 +18,8 @@
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.statusbar.pipeline.ConnectivityInfoProcessor
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
 import dagger.Binds
@@ -34,5 +36,8 @@
     abstract fun bindConnectivityInfoProcessor(cip: ConnectivityInfoProcessor): CoreStartable
 
     @Binds
+    abstract fun connectivityRepository(impl: ConnectivityRepositoryImpl): ConnectivityRepository
+
+    @Binds
     abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
index 2a89309..88d8a86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -34,7 +34,7 @@
     /**
      * Logs a change in one of the **raw inputs** to the connectivity pipeline.
      */
-    fun logInputChange(callbackName: String, changeInfo: String) {
+    fun logInputChange(callbackName: String, changeInfo: String?) {
         buffer.log(
                 SB_LOGGING_TAG,
                 LogLevel.INFO,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt
new file mode 100644
index 0000000..d52d0fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.data.model
+
+import android.content.Context
+import com.android.internal.R
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * A container for all the different types of connectivity slots: wifi, mobile, etc.
+ */
+@SysUISingleton
+class ConnectivitySlots @Inject constructor(context: Context) {
+    private val airplaneSlot: String = context.getString(R.string.status_bar_airplane)
+    private val mobileSlot: String = context.getString(R.string.status_bar_mobile)
+    private val wifiSlot: String = context.getString(R.string.status_bar_wifi)
+    private val ethernetSlot: String = context.getString(R.string.status_bar_ethernet)
+
+    private val slotByName: Map<String, ConnectivitySlot> = mapOf(
+        airplaneSlot to ConnectivitySlot.AIRPLANE,
+        mobileSlot to ConnectivitySlot.MOBILE,
+        wifiSlot to ConnectivitySlot.WIFI,
+        ethernetSlot to ConnectivitySlot.ETHERNET
+    )
+
+    /**
+     * Given a string name of a slot, returns the instance of [ConnectivitySlot] that it corresponds
+     * to, or null if we couldn't find that slot name.
+     */
+    fun getSlotFromName(slotName: String): ConnectivitySlot? {
+        return slotByName[slotName]
+    }
+}
+
+/** The different types of connectivity slots. */
+enum class ConnectivitySlot {
+    AIRPLANE,
+    ETHERNET,
+    MOBILE,
+    WIFI,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
new file mode 100644
index 0000000..6b1750d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.data.repository
+
+import android.content.Context
+import androidx.annotation.ArrayRes
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
+import com.android.systemui.tuner.TunerService
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Provides data related to the connectivity state that needs to be shared across multiple different
+ * types of connectivity (wifi, mobile, ethernet, etc.)
+ */
+interface ConnectivityRepository {
+    /**
+     * Observable for the current set of connectivity icons that should be force-hidden.
+     */
+    val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>>
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class ConnectivityRepositoryImpl @Inject constructor(
+    private val connectivitySlots: ConnectivitySlots,
+    context: Context,
+    dumpManager: DumpManager,
+    logger: ConnectivityPipelineLogger,
+    @Application scope: CoroutineScope,
+    tunerService: TunerService,
+) : ConnectivityRepository, Dumpable {
+    init {
+        dumpManager.registerDumpable("$SB_LOGGING_TAG:ConnectivityRepository", this)
+    }
+
+    // The default set of hidden icons to use if we don't get any from [TunerService].
+    private val defaultHiddenIcons: Set<ConnectivitySlot> =
+            context.resources.getStringArray(DEFAULT_HIDDEN_ICONS_RESOURCE)
+                .asList()
+                .toSlotSet(connectivitySlots)
+
+    override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = conflatedCallbackFlow {
+        val callback = object : TunerService.Tunable {
+            override fun onTuningChanged(key: String, newHideList: String?) {
+                if (key != HIDDEN_ICONS_TUNABLE_KEY) {
+                    return
+                }
+                logger.logInputChange("onTuningChanged", newHideList)
+
+                val outputList = newHideList?.split(",")?.toSlotSet(connectivitySlots)
+                    ?: defaultHiddenIcons
+                trySend(outputList)
+            }
+        }
+        tunerService.addTunable(callback, HIDDEN_ICONS_TUNABLE_KEY)
+
+        awaitClose { tunerService.removeTunable(callback) }
+    }
+        .stateIn(
+            scope,
+            started = SharingStarted.WhileSubscribed(),
+            initialValue = defaultHiddenIcons
+        )
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.apply {
+            println("defaultHiddenIcons=$defaultHiddenIcons")
+        }
+    }
+
+    companion object {
+        @VisibleForTesting
+        internal const val HIDDEN_ICONS_TUNABLE_KEY = StatusBarIconController.ICON_HIDE_LIST
+        @VisibleForTesting
+        @ArrayRes
+        internal val DEFAULT_HIDDEN_ICONS_RESOURCE = R.array.config_statusBarIconsToExclude
+
+        /** Converts a list of string slot names to a set of [ConnectivitySlot] instances. */
+        private fun List<String>.toSlotSet(
+            connectivitySlots: ConnectivitySlots
+        ): Set<ConnectivitySlot> {
+            return this
+                .filter { it.isNotBlank() }
+                .mapNotNull { connectivitySlots.getSlotFromName(it) }
+                .toSet()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index afe19af..952525d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -18,6 +18,8 @@
 
 import android.net.wifi.WifiManager
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import javax.inject.Inject
@@ -33,9 +35,10 @@
  */
 @SysUISingleton
 class WifiInteractor @Inject constructor(
-    repository: WifiRepository,
+    connectivityRepository: ConnectivityRepository,
+    wifiRepository: WifiRepository,
 ) {
-    private val ssid: Flow<String?> = repository.wifiNetwork.map { info ->
+    private val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
         when (info) {
             is WifiNetworkModel.Inactive -> null
             is WifiNetworkModel.CarrierMerged -> null
@@ -49,10 +52,16 @@
     }
 
     /** Our current wifi network. See [WifiNetworkModel]. */
-    val wifiNetwork: Flow<WifiNetworkModel> = repository.wifiNetwork
+    val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
+
+    /** True if we're configured to force-hide the wifi icon and false otherwise. */
+    val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map {
+        it.contains(ConnectivitySlot.WIFI)
+    }
 
     /** True if our wifi network has activity in (download), and false otherwise. */
-    val hasActivityIn: Flow<Boolean> = combine(repository.wifiActivity, ssid) { activity, ssid ->
+    val hasActivityIn: Flow<Boolean> =
+        combine(wifiRepository.wifiActivity, ssid) { activity, ssid ->
             activity.hasActivityIn && ssid != null
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
index 7607ddf..4fad327 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
@@ -24,6 +24,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.R
+import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
 import kotlinx.coroutines.InternalCoroutinesApi
@@ -54,14 +55,15 @@
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
-                    viewModel.wifiIconResId.distinctUntilChanged().collect { iconResId ->
-                        iconView.setImageDrawable(
-                            if (iconResId != null && iconResId > 0) {
-                                iconView.context.getDrawable(iconResId)
-                            } else {
-                                null
-                            }
-                        )
+                    viewModel.wifiIcon.distinctUntilChanged().collect { wifiIcon ->
+                        // TODO(b/238425913): Right now, if !isVisible, there's just an empty space
+                        //  where the wifi icon would be. We need to pipe isVisible through to
+                        //   [ModernStatusBarWifiView.isIconVisible], which is what actually makes
+                        //   the view GONE.
+                        view.isVisible = wifiIcon != null
+                        wifiIcon?.let {
+                            IconViewBinder.bind(wifiIcon, iconView)
+                        }
                     }
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 4fdcc44..3c243ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -16,8 +16,16 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
+import android.content.Context
 import android.graphics.Color
 import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
@@ -29,6 +37,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
@@ -39,6 +48,7 @@
 class WifiViewModel @Inject constructor(
     statusBarPipelineFlags: StatusBarPipelineFlags,
     private val constants: WifiConstants,
+    private val context: Context,
     private val logger: ConnectivityPipelineLogger,
     private val interactor: WifiInteractor,
 ) {
@@ -46,7 +56,7 @@
      * The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
      */
     @DrawableRes
-    val wifiIconResId: Flow<Int?> = interactor.wifiNetwork.map {
+    private val iconResId: Flow<Int?> = interactor.wifiNetwork.map {
         when (it) {
             is WifiNetworkModel.CarrierMerged -> null
             is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
@@ -59,6 +69,49 @@
         }
     }
 
+    /** The content description for the wifi icon. */
+    private val contentDescription: Flow<ContentDescription?> = interactor.wifiNetwork.map {
+        when (it) {
+            is WifiNetworkModel.CarrierMerged -> null
+            is WifiNetworkModel.Inactive ->
+                ContentDescription.Loaded(
+                    "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
+                )
+            is WifiNetworkModel.Active ->
+                when (it.level) {
+                    null -> null
+                    else -> {
+                        val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[it.level])
+                        when {
+                            it.isValidated -> ContentDescription.Loaded(levelDesc)
+                            else -> ContentDescription.Loaded(
+                                "$levelDesc,${context.getString(NO_INTERNET)}"
+                            )
+                        }
+                    }
+                }
+        }
+    }
+
+    /**
+     * The wifi icon that should be displayed. Null if we shouldn't display any icon.
+     */
+    val wifiIcon: Flow<Icon?> = combine(
+            interactor.isForceHidden,
+            iconResId,
+            contentDescription,
+        ) { isForceHidden, iconResId, contentDescription ->
+            when {
+                isForceHidden ||
+                    iconResId == null ||
+                    iconResId <= 0 -> null
+                else -> Icon.Resource(iconResId, contentDescription)
+            }
+        }
+
+    /**
+     * True if the activity in icon should be displayed and false otherwise.
+     */
     val isActivityInVisible: Flow<Boolean>
         get() =
             if (!constants.shouldShowActivityConfig) {
@@ -74,4 +127,10 @@
     } else {
         flowOf(Color.CYAN)
     }
+
+    companion object {
+        @StringRes
+        @VisibleForTesting
+        internal val NO_INTERNET = R.string.data_connection_no_internet
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index bdac888..f4d08e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -31,6 +31,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
@@ -60,6 +61,7 @@
     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
             new UpdateMonitorCallback();
     private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
+    private final KeyguardUpdateMonitorLogger mLogger;
 
     private boolean mCanDismissLockScreen;
     private boolean mShowing;
@@ -107,8 +109,10 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             LockPatternUtils lockPatternUtils,
             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
+            KeyguardUpdateMonitorLogger logger,
             DumpManager dumpManager) {
         mContext = context;
+        mLogger = logger;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
@@ -245,6 +249,8 @@
             mTrusted = trusted;
             mTrustManaged = trustManaged;
             mFaceAuthEnabled = faceAuthEnabled;
+            mLogger.logKeyguardStateUpdate(
+                    mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
             notifyUnlockedChanged();
         }
         Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e2d1601..3b8ed33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -86,6 +86,7 @@
 import com.android.systemui.telephony.TelephonyListenerManager;
 import com.android.systemui.user.CreateUserActivity;
 import com.android.systemui.user.data.source.UserRecord;
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -100,14 +101,20 @@
 
 import javax.inject.Inject;
 
+import kotlinx.coroutines.flow.Flow;
+import kotlinx.coroutines.flow.MutableStateFlow;
+import kotlinx.coroutines.flow.StateFlowKt;
+
 /**
  * Keeps a list of all users on the device for user switching.
  */
 @SysUISingleton
 public class UserSwitcherController implements Dumpable {
 
-    public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
-    public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
+    public static final float USER_SWITCH_ENABLED_ALPHA =
+            LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA;
+    public static final float USER_SWITCH_DISABLED_ALPHA =
+            LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA;
 
     private static final String TAG = "UserSwitcherController";
     private static final boolean DEBUG = false;
@@ -155,7 +162,8 @@
     private boolean mSimpleUserSwitcher;
     // When false, there won't be any visual affordance to add a new user from the keyguard even if
     // the user is unlocked
-    private boolean mAddUsersFromLockScreen;
+    private final MutableStateFlow<Boolean> mAddUsersFromLockScreen =
+            StateFlowKt.MutableStateFlow(false);
     private boolean mUserSwitcherEnabled;
     @VisibleForTesting
     boolean mPauseRefreshUsers;
@@ -258,8 +266,11 @@
             @Override
             public void onChange(boolean selfChange) {
                 mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
-                mAddUsersFromLockScreen = mGlobalSettings.getIntForUser(
-                        Settings.Global.ADD_USERS_WHEN_LOCKED, 0, UserHandle.USER_SYSTEM) != 0;
+                mAddUsersFromLockScreen.setValue(
+                        mGlobalSettings.getIntForUser(
+                                Settings.Global.ADD_USERS_WHEN_LOCKED,
+                                0,
+                                UserHandle.USER_SYSTEM) != 0);
                 mUserSwitcherEnabled = mGlobalSettings.getIntForUser(
                         Settings.Global.USER_SWITCHER_ENABLED, 0, UserHandle.USER_SYSTEM) != 0;
                 refreshUsers(UserHandle.USER_NULL);
@@ -323,7 +334,6 @@
         }
         mForcePictureLoadForUserId.clear();
 
-        final boolean addUsersWhenLocked = mAddUsersFromLockScreen;
         mBgExecutor.execute(() ->  {
             List<UserInfo> infos = mUserManager.getAliveUsers();
             if (infos == null) {
@@ -434,7 +444,7 @@
     }
 
     boolean anyoneCanCreateUsers() {
-        return systemCanCreateUsers() && mAddUsersFromLockScreen;
+        return systemCanCreateUsers() && mAddUsersFromLockScreen.getValue();
     }
 
     boolean canCreateGuest(boolean hasExistingGuest) {
@@ -450,7 +460,7 @@
     }
 
     boolean createIsRestricted() {
-        return !mAddUsersFromLockScreen;
+        return !mAddUsersFromLockScreen.getValue();
     }
 
     boolean canCreateSupervisedUser() {
@@ -516,17 +526,48 @@
         return null;
     }
 
+    /**
+     * Notifies that a user has been selected.
+     *
+     * <p>This will trigger the right user journeys to create a guest user, switch users, and/or
+     * navigate to the correct destination.
+     *
+     * <p>If a user with the given ID is not found, this method is a no-op.
+     *
+     * @param userId The ID of the user to switch to.
+     * @param dialogShower An optional {@link DialogShower} in case we need to show dialogs.
+     */
+    public void onUserSelected(int userId, @Nullable DialogShower dialogShower) {
+        UserRecord userRecord = mUsers.stream()
+                .filter(x -> x.resolveId() == userId)
+                .findFirst()
+                .orElse(null);
+        if (userRecord == null) {
+            return;
+        }
+
+        onUserListItemClicked(userRecord, dialogShower);
+    }
+
+    /** Whether it is allowed to add users while the device is locked. */
+    public Flow<Boolean> getAddUsersFromLockScreen() {
+        return mAddUsersFromLockScreen;
+    }
+
+    /** Returns {@code true} if the guest user is configured to always be present on the device. */
+    public boolean isGuestUserAutoCreated() {
+        return mGuestUserAutoCreated;
+    }
+
+    /** Returns {@code true} if the guest user is currently being reset. */
+    public boolean isGuestUserResetting() {
+        return mGuestIsResetting.get();
+    }
+
     @VisibleForTesting
     void onUserListItemClicked(UserRecord record, DialogShower dialogShower) {
         if (record.isGuest && record.info == null) {
-            // No guest user. Create one.
-            createGuestAsync(guestId -> {
-                // guestId may be USER_NULL if we haven't reloaded the user list yet.
-                if (guestId != UserHandle.USER_NULL) {
-                    mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
-                    onUserListItemClicked(guestId, record, dialogShower);
-                }
-            });
+            createAndSwitchToGuestUser(dialogShower);
         } else if (record.isAddUser) {
             showAddUserDialog(dialogShower);
         } else if (record.isAddSupervisedUser) {
@@ -604,7 +645,23 @@
         }
     }
 
-    private void showAddUserDialog(DialogShower dialogShower) {
+    /**
+     * Creates and switches to the guest user.
+     */
+    public void createAndSwitchToGuestUser(@Nullable DialogShower dialogShower) {
+        createGuestAsync(guestId -> {
+            // guestId may be USER_NULL if we haven't reloaded the user list yet.
+            if (guestId != UserHandle.USER_NULL) {
+                mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
+                onUserListItemClicked(guestId, UserRecord.createForGuest(), dialogShower);
+            }
+        });
+    }
+
+    /**
+     * Shows the add user dialog.
+     */
+    public void showAddUserDialog(@Nullable DialogShower dialogShower) {
         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
             mAddUserDialog.cancel();
         }
@@ -620,7 +677,10 @@
         }
     }
 
-    private void startSupervisedUserActivity() {
+    /**
+     * Starts an activity to add a supervised user to the device.
+     */
+    public void startSupervisedUserActivity() {
         final Intent intent = new Intent()
                 .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
                 .setPackage(mCreateSupervisedUserPackage)
@@ -772,7 +832,7 @@
      * Removes guest user and switches to target user. The guest must be the current user and its id
      * must be {@code guestUserId}.
      *
-     * <p>If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in
+     * <p>If {@code targetUserId} is {@link UserHandle#USER_NULL}, then create a new guest user in
      * the foreground, and immediately switch to it. This is used for wiping the current guest and
      * replacing it with a new one.
      *
@@ -782,11 +842,11 @@
      * <p>If device is configured with {@link
      * com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a
      * new one is created in the background. This has no effect if {@code targetUserId} is {@link
-     * UserHandle.USER_NULL}.
+     * UserHandle#USER_NULL}.
      *
      * @param guestUserId id of the guest user to remove
      * @param targetUserId id of the user to switch to after guest is removed. If {@link
-     * UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
+     * UserHandle#USER_NULL}, then switch immediately to the newly created guest user.
      */
     public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
         UserInfo currentUser = mUserTracker.getUserInfo();
@@ -839,7 +899,7 @@
      * user.
      *
      * @param guestUserId user id of the guest user to exit
-     * @param targetUserId user id of the guest user to exit, set to UserHandle.USER_NULL when
+     * @param targetUserId user id of the guest user to exit, set to UserHandle#USER_NULL when
      *                       target user id is not known
      * @param forceRemoveGuestOnExit true: remove guest before switching user,
      *                               false: remove guest only if its ephemeral, else keep guest
@@ -952,7 +1012,7 @@
      * {@link UserManager} to create a new one.
      *
      * @return The multi-user user ID of the newly created guest user, or
-     * {@link UserHandle.USER_NULL} if the guest couldn't be created.
+     * {@link UserHandle#USER_NULL} if the guest couldn't be created.
      */
     public @UserIdInt int createGuest() {
         UserInfo guest;
@@ -1062,38 +1122,11 @@
         }
 
         public String getName(Context context, UserRecord item) {
-            if (item.isGuest) {
-                if (item.isCurrent) {
-                    return context.getString(
-                            com.android.settingslib.R.string.guest_exit_quick_settings_button);
-                } else {
-                    if (item.info != null) {
-                        return context.getString(com.android.internal.R.string.guest_name);
-                    } else {
-                        if (mController.mGuestUserAutoCreated) {
-                            // If mGuestIsResetting=true, we expect the guest user to be created
-                            // shortly, so display a "Resetting guest..." as an indicator that we
-                            // are busy. Otherwise, if mGuestIsResetting=false, we probably failed
-                            // to create a guest at some point. In this case, always show guest
-                            // nickname instead of "Add guest" to make it seem as though the device
-                            // always has a guest ready for use.
-                            return context.getString(
-                                    mController.mGuestIsResetting.get()
-                                            ? com.android.settingslib.R.string.guest_resetting
-                                            : com.android.internal.R.string.guest_name);
-                        } else {
-                            // we always show "guest" as string, instead of "add guest"
-                            return context.getString(com.android.internal.R.string.guest_name);
-                        }
-                    }
-                }
-            } else if (item.isAddUser) {
-                return context.getString(com.android.settingslib.R.string.user_add_user);
-            } else if (item.isAddSupervisedUser) {
-                return context.getString(R.string.add_user_supervised);
-            } else {
-                return item.info.name;
-            }
+            return LegacyUserUiHelper.getUserRecordName(
+                    context,
+                    item,
+                    mController.isGuestUserAutoCreated(),
+                    mController.isGuestUserResetting());
         }
 
         protected static ColorFilter getDisabledUserAvatarColorFilter() {
@@ -1103,17 +1136,8 @@
         }
 
         protected static Drawable getIconDrawable(Context context, UserRecord item) {
-            int iconRes;
-            if (item.isAddUser) {
-                iconRes = R.drawable.ic_add;
-            } else if (item.isGuest) {
-                iconRes = R.drawable.ic_account_circle;
-            } else if (item.isAddSupervisedUser) {
-                iconRes = R.drawable.ic_add_supervised_user;
-            } else {
-                iconRes = R.drawable.ic_avatar_user;
-            }
-
+            int iconRes = LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
+                    item.isAddUser, item.isGuest, item.isAddSupervisedUser);
             return context.getDrawable(iconRes);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
new file mode 100644
index 0000000..a52e2af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import android.annotation.LayoutRes
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.os.PowerManager
+import android.os.SystemClock
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS
+import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS
+import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT
+import androidx.annotation.CallSuper
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.concurrency.DelayableExecutor
+
+/**
+ * A generic controller that can temporarily display a new view in a new window.
+ *
+ * Subclasses need to override and implement [updateView], which is where they can control what
+ * gets displayed to the user.
+ *
+ * The generic type T is expected to contain all the information necessary for the subclasses to
+ * display the view in a certain state, since they receive <T> in [updateView].
+ *
+ * @property windowTitle the title to use for the window that displays the temporary view. Should be
+ *   normally cased, like "Window Title".
+ * @property wakeReason a string used for logging if we needed to wake the screen in order to
+ *   display the temporary view. Should be screaming snake cased, like WAKE_REASON.
+ */
+abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger>(
+    internal val context: Context,
+    internal val logger: U,
+    internal val windowManager: WindowManager,
+    @Main private val mainExecutor: DelayableExecutor,
+    private val accessibilityManager: AccessibilityManager,
+    private val configurationController: ConfigurationController,
+    private val powerManager: PowerManager,
+    @LayoutRes private val viewLayoutRes: Int,
+    private val windowTitle: String,
+    private val wakeReason: String,
+) {
+    /**
+     * Window layout params that will be used as a starting point for the [windowLayoutParams] of
+     * all subclasses.
+     */
+    @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
+    internal val commonWindowLayoutParams = WindowManager.LayoutParams().apply {
+        width = WindowManager.LayoutParams.WRAP_CONTENT
+        height = WindowManager.LayoutParams.WRAP_CONTENT
+        type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
+        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+        title = windowTitle
+        format = PixelFormat.TRANSLUCENT
+        setTrustedOverlay()
+    }
+
+    /**
+     * The window layout parameters we'll use when attaching the view to a window.
+     *
+     * Subclasses must override this to provide their specific layout params, and they should use
+     * [commonWindowLayoutParams] as part of their layout params.
+     */
+    internal abstract val windowLayoutParams: WindowManager.LayoutParams
+
+    /** The view currently being displayed. Null if the view is not being displayed. */
+    private var view: ViewGroup? = null
+
+    /** The info currently being displayed. Null if the view is not being displayed. */
+    internal var info: T? = null
+
+    /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
+    private var cancelViewTimeout: Runnable? = null
+
+    /**
+     * Displays the view with the provided [newInfo].
+     *
+     * This method handles inflating and attaching the view, then delegates to [updateView] to
+     * display the correct information in the view.
+     */
+    fun displayView(newInfo: T) {
+        val currentView = view
+
+        if (currentView != null) {
+            updateView(newInfo, currentView)
+        } else {
+            // The view is new, so set up all our callbacks and inflate the view
+            configurationController.addCallback(displayScaleListener)
+            // Wake the screen if necessary so the user will see the view. (Per b/239426653, we want
+            // the view to show over the dream state, so we should only wake up if the screen is
+            // completely off.)
+            if (!powerManager.isScreenOn) {
+                powerManager.wakeUp(
+                        SystemClock.uptimeMillis(),
+                        PowerManager.WAKE_REASON_APPLICATION,
+                        "com.android.systemui:$wakeReason",
+                )
+            }
+            logger.logChipAddition()
+            inflateAndUpdateView(newInfo)
+        }
+
+        // Cancel and re-set the view timeout each time we get a new state.
+        val timeout = accessibilityManager.getRecommendedTimeoutMillis(
+            newInfo.getTimeoutMs().toInt(),
+            // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
+            // include it just to be safe.
+            FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
+       )
+        cancelViewTimeout?.run()
+        cancelViewTimeout = mainExecutor.executeDelayed(
+            { removeView(TemporaryDisplayRemovalReason.REASON_TIMEOUT) },
+            timeout.toLong()
+        )
+    }
+
+    /** Inflates a new view, updates it with [newInfo], and adds the view to the window. */
+    private fun inflateAndUpdateView(newInfo: T) {
+        val newView = LayoutInflater
+                .from(context)
+                .inflate(viewLayoutRes, null) as ViewGroup
+        view = newView
+        updateView(newInfo, newView)
+        windowManager.addView(newView, windowLayoutParams)
+        animateViewIn(newView)
+    }
+
+    /** Removes then re-inflates the view. */
+    private fun reinflateView() {
+        val currentInfo = info
+        if (view == null || currentInfo == null) { return }
+
+        windowManager.removeView(view)
+        inflateAndUpdateView(currentInfo)
+    }
+
+    private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
+        override fun onDensityOrFontScaleChanged() {
+            reinflateView()
+        }
+    }
+
+    /**
+     * Hides the view.
+     *
+     * @param removalReason a short string describing why the view was removed (timeout, state
+     *     change, etc.)
+     */
+    open fun removeView(removalReason: String) {
+        if (view == null) { return }
+        logger.logChipRemoval(removalReason)
+        configurationController.removeCallback(displayScaleListener)
+        windowManager.removeView(view)
+        view = null
+        info = null
+        // No need to time the view out since it's already gone
+        cancelViewTimeout?.run()
+    }
+
+    /**
+     * A method implemented by subclasses to update [currentView] based on [newInfo].
+     */
+    @CallSuper
+    open fun updateView(newInfo: T, currentView: ViewGroup) {
+        info = newInfo
+    }
+
+    /**
+     * A method that can be implemented by subclasses to do custom animations for when the view
+     * appears.
+     */
+    open fun animateViewIn(view: ViewGroup) {}
+}
+
+object TemporaryDisplayRemovalReason {
+    const val REASON_TIMEOUT = "TIMEOUT"
+    const val REASON_SCREEN_TAP = "SCREEN_TAP"
+}
+
+private data class IconInfo(
+    val iconName: String,
+    val icon: Drawable,
+    /** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
+    val isAppIcon: Boolean
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
index a29c588..4fe753a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
 
 /**
- * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ * A superclass view state used with [TemporaryViewDisplayController].
  */
-interface ChipInfoCommon {
+interface TemporaryViewInfo {
     /**
-     * Returns the amount of time the given chip state should display on the screen before it times
+     * Returns the amount of time the given view state should display on the screen before it times
      * out and disappears.
      */
-    fun getTimeoutMs(): Long
+    fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
 }
 
 const val DEFAULT_TIMEOUT_MILLIS = 10000L
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
new file mode 100644
index 0000000..606a11a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+
+/** A logger for temporary view changes -- see [TemporaryViewDisplayController]. */
+open class TemporaryViewLogger(
+    internal val buffer: LogBuffer,
+    internal val tag: String,
+) {
+    /** Logs that we added the chip to a new window. */
+    fun logChipAddition() {
+        buffer.log(tag, LogLevel.DEBUG, {}, { "Chip added" })
+    }
+
+    /** Logs that we removed the chip for the given [reason]. */
+    fun logChipRemoval(reason: String) {
+        buffer.log(tag, LogLevel.DEBUG, { str1 = reason }, { "Chip removed due to $str1" })
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index 8f127fd..0f06144 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -18,22 +18,31 @@
 
 import android.content.Context
 import android.hardware.devicestate.DeviceStateManager
-import android.os.Handler
 import android.os.PowerManager
 import android.provider.Settings
+import androidx.annotation.VisibleForTesting
 import androidx.core.view.OneShotPreDrawListener
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.ScreenOffAnimation
 import com.android.systemui.statusbar.policy.CallbackController
 import com.android.systemui.unfold.FoldAodAnimationController.FoldAodAnimationStatus
+import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.settings.GlobalSettings
-import java.util.concurrent.Executor
+import dagger.Lazy
 import java.util.function.Consumer
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 
 /**
  * Controls folding to AOD animation: when AOD is enabled and foldable device is folded we play a
@@ -43,16 +52,16 @@
 class FoldAodAnimationController
 @Inject
 constructor(
-    @Main private val handler: Handler,
-    @Main private val executor: Executor,
+    @Main private val executor: DelayableExecutor,
     private val context: Context,
     private val deviceStateManager: DeviceStateManager,
     private val wakefulnessLifecycle: WakefulnessLifecycle,
     private val globalSettings: GlobalSettings,
     private val latencyTracker: LatencyTracker,
+    private val keyguardInteractor: Lazy<KeyguardInteractor>,
 ) : CallbackController<FoldAodAnimationStatus>, ScreenOffAnimation, WakefulnessLifecycle.Observer {
 
-    private lateinit var mCentralSurfaces: CentralSurfaces
+    private lateinit var centralSurfaces: CentralSurfaces
 
     private var isFolded = false
     private var isFoldHandled = true
@@ -64,12 +73,13 @@
 
     private var shouldPlayAnimation = false
     private var isAnimationPlaying = false
+    private var cancelAnimation: Runnable? = null
 
     private val statusListeners = arrayListOf<FoldAodAnimationStatus>()
     private val foldToAodLatencyTracker = FoldToAodLatencyTracker()
 
     private val startAnimationRunnable = Runnable {
-        mCentralSurfaces.notificationPanelViewController.startFoldToAodAnimation(
+        centralSurfaces.notificationPanelViewController.startFoldToAodAnimation(
             /* startAction= */ { foldToAodLatencyTracker.onAnimationStarted() },
             /* endAction= */ { setAnimationState(playing = false) },
             /* cancelAction= */ { setAnimationState(playing = false) },
@@ -77,10 +87,14 @@
     }
 
     override fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) {
-        this.mCentralSurfaces = centralSurfaces
+        this.centralSurfaces = centralSurfaces
 
         deviceStateManager.registerCallback(executor, FoldListener())
         wakefulnessLifecycle.addObserver(this)
+
+        centralSurfaces.notificationPanelViewController.view.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.STARTED) { listenForDozing(this) }
+        }
     }
 
     /** Returns true if we should run fold to AOD animation */
@@ -94,7 +108,7 @@
     override fun startAnimation(): Boolean =
         if (shouldStartAnimation()) {
             setAnimationState(playing = true)
-            mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
+            centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
             true
         } else {
             setAnimationState(playing = false)
@@ -104,8 +118,8 @@
     override fun onStartedWakingUp() {
         if (isAnimationPlaying) {
             foldToAodLatencyTracker.cancel()
-            handler.removeCallbacks(startAnimationRunnable)
-            mCentralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
+            cancelAnimation?.run()
+            centralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
         }
 
         setAnimationState(playing = false)
@@ -138,13 +152,13 @@
             // We should play the folding to AOD animation
 
             setAnimationState(playing = true)
-            mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
+            centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
 
             // We don't need to wait for the scrim as it is already displayed
             // but we should wait for the initial animation preparations to be drawn
             // (setting initial alpha/translation)
             OneShotPreDrawListener.add(
-                mCentralSurfaces.notificationPanelViewController.view,
+                centralSurfaces.notificationPanelViewController.view,
                 onReady
             )
         } else {
@@ -165,18 +179,14 @@
 
     fun onScreenTurnedOn() {
         if (shouldPlayAnimation) {
-            handler.removeCallbacks(startAnimationRunnable)
+            cancelAnimation?.run()
 
             // Post starting the animation to the next frame to avoid junk due to inset changes
-            handler.post(startAnimationRunnable)
+            cancelAnimation = executor.executeDelayed(startAnimationRunnable, /* delayMillis= */ 0)
             shouldPlayAnimation = false
         }
     }
 
-    fun setIsDozing(dozing: Boolean) {
-        isDozing = dozing
-    }
-
     override fun isAnimationPlaying(): Boolean = isAnimationPlaying
 
     override fun isKeyguardHideDelayed(): Boolean = isAnimationPlaying()
@@ -204,6 +214,11 @@
         statusListeners.remove(listener)
     }
 
+    @VisibleForTesting
+    internal suspend fun listenForDozing(scope: CoroutineScope): Job {
+        return scope.launch { keyguardInteractor.get().isDozing.collect { isDozing = it } }
+    }
+
     interface FoldAodAnimationStatus {
         fun onFoldToAodAnimationChanged()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
index 469d54f..5b522dc 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 
 import com.android.settingslib.users.EditUserInfoController;
+import com.android.systemui.user.data.repository.UserRepositoryModule;
 
 import dagger.Binds;
 import dagger.Module;
@@ -29,7 +30,11 @@
 /**
  * Dagger module for User related classes.
  */
-@Module
+@Module(
+        includes = {
+                UserRepositoryModule.class,
+        }
+)
 public abstract class UserModule {
 
     private static final String FILE_PROVIDER_AUTHORITY = "com.android.systemui.fileprovider";
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index ff0f0d4..d43f739 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -27,6 +27,7 @@
 import android.os.Bundle
 import android.os.UserManager
 import android.provider.Settings
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.MotionEvent
 import android.view.View
@@ -35,8 +36,11 @@
 import android.widget.ArrayAdapter
 import android.widget.ImageView
 import android.widget.TextView
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
 import androidx.activity.ComponentActivity
 import androidx.constraintlayout.helper.widget.Flow
+import androidx.lifecycle.ViewModelProvider
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.util.UserIcons
 import com.android.settingslib.Utils
@@ -44,6 +48,8 @@
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
 import com.android.systemui.settings.UserTracker
@@ -52,6 +58,9 @@
 import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA
 import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA
 import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.ui.binder.UserSwitcherViewBinder
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import dagger.Lazy
 import javax.inject.Inject
 import kotlin.math.ceil
 
@@ -60,14 +69,15 @@
 /**
  * Support a fullscreen user switcher
  */
-class UserSwitcherActivity @Inject constructor(
+open class UserSwitcherActivity @Inject constructor(
     private val userSwitcherController: UserSwitcherController,
     private val broadcastDispatcher: BroadcastDispatcher,
-    private val layoutInflater: LayoutInflater,
     private val falsingCollector: FalsingCollector,
     private val falsingManager: FalsingManager,
     private val userManager: UserManager,
-    private val userTracker: UserTracker
+    private val userTracker: UserTracker,
+    private val flags: FeatureFlags,
+    private val viewModelFactory: Lazy<UserSwitcherViewModel.Factory>,
 ) : ComponentActivity() {
 
     private lateinit var parent: UserSwitcherRootView
@@ -75,6 +85,7 @@
     private var popupMenu: UserSwitcherPopupMenu? = null
     private lateinit var addButton: View
     private var addUserRecords = mutableListOf<UserRecord>()
+    private val onBackCallback = OnBackInvokedCallback { finish() }
     private val userSwitchedCallback: UserTracker.Callback = object : UserTracker.Callback {
         override fun onUserChanged(newUser: Int, userContext: Context) {
             finish()
@@ -93,119 +104,35 @@
             false /* isAddSupervisedUser */
         )
 
-    private val adapter = object : BaseUserAdapter(userSwitcherController) {
-        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
-            val item = getItem(position)
-            var view = convertView as ViewGroup?
-            if (view == null) {
-                view = layoutInflater.inflate(
-                    R.layout.user_switcher_fullscreen_item,
-                    parent,
-                    false
-                ) as ViewGroup
-            }
-            (view.getChildAt(0) as ImageView).apply {
-                setImageDrawable(getDrawable(item))
-            }
-            (view.getChildAt(1) as TextView).apply {
-                setText(getName(getContext(), item))
-            }
-
-            view.setEnabled(item.isSwitchToEnabled)
-            view.setAlpha(
-                if (view.isEnabled()) {
-                    USER_SWITCH_ENABLED_ALPHA
-                } else {
-                    USER_SWITCH_DISABLED_ALPHA
-                }
-            )
-            view.setTag(USER_VIEW)
-            return view
-        }
-
-        override fun getName(context: Context, item: UserRecord): String {
-            return if (item == manageUserRecord) {
-                getString(R.string.manage_users)
-            } else {
-                super.getName(context, item)
-            }
-        }
-
-        fun findUserIcon(item: UserRecord): Drawable {
-            if (item == manageUserRecord) {
-                return getDrawable(R.drawable.ic_manage_users)
-            }
-            if (item.info == null) {
-                return getIconDrawable(this@UserSwitcherActivity, item)
-            }
-            val userIcon = userManager.getUserIcon(item.info.id)
-            if (userIcon != null) {
-                return BitmapDrawable(userIcon)
-            }
-            return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
-        }
-
-        fun getTotalUserViews(): Int {
-            return users.count { item ->
-                !doNotRenderUserView(item)
-            }
-        }
-
-        fun doNotRenderUserView(item: UserRecord): Boolean {
-            return item.isAddUser ||
-                    item.isAddSupervisedUser ||
-                    item.isGuest && item.info == null
-        }
-
-        private fun getDrawable(item: UserRecord): Drawable {
-            var drawable = if (item.isGuest) {
-                getDrawable(R.drawable.ic_account_circle)
-            } else {
-                findUserIcon(item)
-            }
-            drawable.mutate()
-
-            if (!item.isCurrent && !item.isSwitchToEnabled) {
-                drawable.setTint(
-                    resources.getColor(
-                        R.color.kg_user_switcher_restricted_avatar_icon_color,
-                        getTheme()
-                    )
-                )
-            }
-
-            val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
-                as LayerDrawable
-            if (item == userSwitcherController.getCurrentUserRecord()) {
-                (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
-                    val stroke = resources
-                        .getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
-                    val color = Utils.getColorAttrDefaultColor(
-                        this@UserSwitcherActivity,
-                        com.android.internal.R.attr.colorAccentPrimary
-                    )
-
-                    setStroke(stroke, color)
-                }
-            }
-
-            ld.setDrawableByLayerId(R.id.user_avatar, drawable)
-            return ld
-        }
-
-        override fun notifyDataSetChanged() {
-            super.notifyDataSetChanged()
-            buildUserViews()
-        }
-    }
+    private val adapter: UserAdapter by lazy { UserAdapter() }
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        createActivity()
+    }
 
+    @VisibleForTesting
+    fun createActivity() {
         setContentView(R.layout.user_switcher_fullscreen)
-        window.decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
+        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
+        if (isUsingModernArchitecture()) {
+            Log.d(TAG, "Using modern architecture.")
+            val viewModel = ViewModelProvider(
+                this, viewModelFactory.get())[UserSwitcherViewModel::class.java]
+            UserSwitcherViewBinder.bind(
+                view = requireViewById(R.id.user_switcher_root),
+                viewModel = viewModel,
+                lifecycleOwner = this,
+                layoutInflater = layoutInflater,
+                falsingCollector = falsingCollector,
+                onFinish = this::finish,
+            )
+            return
+        } else {
+            Log.d(TAG, "Not using modern architecture.")
+        }
 
         parent = requireViewById<UserSwitcherRootView>(R.id.user_switcher_root)
 
@@ -228,6 +155,9 @@
             }
         }
 
+        onBackInvokedDispatcher.registerOnBackInvokedCallback(
+                OnBackInvokedDispatcher.PRIORITY_DEFAULT, onBackCallback)
+
         userSwitcherController.init(parent)
         initBroadcastReceiver()
 
@@ -346,12 +276,24 @@
     }
 
     override fun onBackPressed() {
+        if (isUsingModernArchitecture()) {
+            return super.onBackPressed()
+        }
+
         finish()
     }
 
     override fun onDestroy() {
         super.onDestroy()
+        if (isUsingModernArchitecture()) {
+            return
+        }
+        destroyActivity()
+    }
 
+    @VisibleForTesting
+    fun destroyActivity() {
+        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackCallback)
         broadcastDispatcher.unregisterReceiver(broadcastReceiver)
         userTracker.removeCallback(userSwitchedCallback)
     }
@@ -376,6 +318,10 @@
         return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt()
     }
 
+    private fun isUsingModernArchitecture(): Boolean {
+        return flags.isEnabled(Flags.MODERN_USER_SWITCHER_ACTIVITY)
+    }
+
     private class ItemAdapter(
         val parentContext: Context,
         val resource: Int,
@@ -398,4 +344,114 @@
             return view
         }
     }
+
+    private inner class UserAdapter : BaseUserAdapter(userSwitcherController) {
+        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+            val item = getItem(position)
+            var view = convertView as ViewGroup?
+            if (view == null) {
+                view = layoutInflater.inflate(
+                    R.layout.user_switcher_fullscreen_item,
+                    parent,
+                    false
+                ) as ViewGroup
+            }
+            (view.getChildAt(0) as ImageView).apply {
+                setImageDrawable(getDrawable(item))
+            }
+            (view.getChildAt(1) as TextView).apply {
+                setText(getName(getContext(), item))
+            }
+
+            view.setEnabled(item.isSwitchToEnabled)
+            view.setAlpha(
+                if (view.isEnabled()) {
+                    USER_SWITCH_ENABLED_ALPHA
+                } else {
+                    USER_SWITCH_DISABLED_ALPHA
+                }
+            )
+            view.setTag(USER_VIEW)
+            return view
+        }
+
+        override fun getName(context: Context, item: UserRecord): String {
+            return if (item == manageUserRecord) {
+                getString(R.string.manage_users)
+            } else {
+                super.getName(context, item)
+            }
+        }
+
+        fun findUserIcon(item: UserRecord): Drawable {
+            if (item == manageUserRecord) {
+                return getDrawable(R.drawable.ic_manage_users)
+            }
+            if (item.info == null) {
+                return getIconDrawable(this@UserSwitcherActivity, item)
+            }
+            val userIcon = userManager.getUserIcon(item.info.id)
+            if (userIcon != null) {
+                return BitmapDrawable(userIcon)
+            }
+            return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
+        }
+
+        fun getTotalUserViews(): Int {
+            return users.count { item ->
+                !doNotRenderUserView(item)
+            }
+        }
+
+        fun doNotRenderUserView(item: UserRecord): Boolean {
+            return item.isAddUser ||
+                    item.isAddSupervisedUser ||
+                    item.isGuest && item.info == null
+        }
+
+        private fun getDrawable(item: UserRecord): Drawable {
+            var drawable = if (item.isGuest) {
+                getDrawable(R.drawable.ic_account_circle)
+            } else {
+                findUserIcon(item)
+            }
+            drawable.mutate()
+
+            if (!item.isCurrent && !item.isSwitchToEnabled) {
+                drawable.setTint(
+                    resources.getColor(
+                        R.color.kg_user_switcher_restricted_avatar_icon_color,
+                        getTheme()
+                    )
+                )
+            }
+
+            val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
+                    as LayerDrawable
+            if (item == userSwitcherController.getCurrentUserRecord()) {
+                (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
+                    val stroke = resources
+                        .getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
+                    val color = Utils.getColorAttrDefaultColor(
+                        this@UserSwitcherActivity,
+                        com.android.internal.R.attr.colorAccentPrimary
+                    )
+
+                    setStroke(stroke, color)
+                }
+            }
+
+            ld.setDrawableByLayerId(R.id.user_avatar, drawable)
+            return ld
+        }
+
+        override fun notifyDataSetChanged() {
+            super.notifyDataSetChanged()
+            buildUserViews()
+        }
+    }
+
+    companion object {
+        private const val TAG = "UserSwitcherActivity"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
new file mode 100644
index 0000000..305b5ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.data.repository
+
+import android.content.Context
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.os.UserManager
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.internal.util.UserIcons
+import com.android.systemui.R
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Acts as source of truth for user related data.
+ *
+ * Abstracts-away data sources and their schemas so the rest of the app doesn't need to worry about
+ * upstream changes.
+ */
+interface UserRepository {
+    /** List of all users on the device. */
+    val users: Flow<List<UserModel>>
+
+    /** The currently-selected user. */
+    val selectedUser: Flow<UserModel>
+
+    /** List of available user-related actions. */
+    val actions: Flow<List<UserActionModel>>
+
+    /** Whether actions are available even when locked. */
+    val isActionableWhenLocked: Flow<Boolean>
+
+    /** Whether the device is configured to always have a guest user available. */
+    val isGuestUserAutoCreated: Boolean
+
+    /** Whether the guest user is currently being reset. */
+    val isGuestUserResetting: Boolean
+}
+
+@SysUISingleton
+class UserRepositoryImpl
+@Inject
+constructor(
+    @Application private val appContext: Context,
+    private val manager: UserManager,
+    controller: UserSwitcherController,
+) : UserRepository {
+
+    private val userRecords: Flow<List<UserRecord>> = conflatedCallbackFlow {
+        fun send() {
+            trySendWithFailureLogging(
+                controller.users,
+                TAG,
+            )
+        }
+
+        val callback = UserSwitcherController.UserSwitchCallback { send() }
+
+        controller.addUserSwitchCallback(callback)
+        send()
+
+        awaitClose { controller.removeUserSwitchCallback(callback) }
+    }
+
+    override val users: Flow<List<UserModel>> =
+        userRecords.map { records -> records.filter { it.isUser() }.map { it.toUserModel() } }
+
+    override val selectedUser: Flow<UserModel> =
+        users.map { users -> users.first { user -> user.isSelected } }
+
+    override val actions: Flow<List<UserActionModel>> =
+        userRecords.map { records -> records.filter { it.isNotUser() }.map { it.toActionModel() } }
+
+    override val isActionableWhenLocked: Flow<Boolean> = controller.addUsersFromLockScreen
+
+    override val isGuestUserAutoCreated: Boolean = controller.isGuestUserAutoCreated
+
+    override val isGuestUserResetting: Boolean = controller.isGuestUserResetting
+
+    private fun UserRecord.isUser(): Boolean {
+        return when {
+            isAddUser -> false
+            isAddSupervisedUser -> false
+            isGuest -> info != null
+            else -> true
+        }
+    }
+
+    private fun UserRecord.isNotUser(): Boolean {
+        return !isUser()
+    }
+
+    private fun UserRecord.toUserModel(): UserModel {
+        return UserModel(
+            id = resolveId(),
+            name = getUserName(this),
+            image = getUserImage(this),
+            isSelected = isCurrent,
+            isSelectable = isSwitchToEnabled || isGuest,
+        )
+    }
+
+    private fun UserRecord.toActionModel(): UserActionModel {
+        return when {
+            isAddUser -> UserActionModel.ADD_USER
+            isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER
+            isGuest -> UserActionModel.ENTER_GUEST_MODE
+            else -> error("Don't know how to convert to UserActionModel: $this")
+        }
+    }
+
+    private fun getUserName(record: UserRecord): Text {
+        val resourceId: Int? = LegacyUserUiHelper.getGuestUserRecordNameResourceId(record)
+        return if (resourceId != null) {
+            Text.Resource(resourceId)
+        } else {
+            Text.Loaded(checkNotNull(record.info).name)
+        }
+    }
+
+    private fun getUserImage(record: UserRecord): Drawable {
+        if (record.isGuest) {
+            return checkNotNull(
+                AppCompatResources.getDrawable(appContext, R.drawable.ic_account_circle)
+            )
+        }
+
+        val userId = checkNotNull(record.info?.id)
+        return manager.getUserIcon(userId)?.let { userSelectedIcon ->
+            BitmapDrawable(userSelectedIcon)
+        }
+            ?: UserIcons.getDefaultUserIcon(appContext.resources, userId, /* light= */ false)
+    }
+
+    companion object {
+        private const val TAG = "UserRepository"
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
index 1de740a..18ae107 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,17 +12,15 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.user.data.repository
 
-import android.annotation.UserIdInt;
-import android.content.Context;
+import dagger.Binds
+import dagger.Module
 
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
+@Module
+interface UserRepositoryModule {
+    @Binds fun bindRepository(impl: UserRepositoryImpl): UserRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
index 6ab6d7d..cf6da9a 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
@@ -20,38 +20,29 @@
 import android.graphics.Bitmap
 import android.os.UserHandle
 
-/**
- * Encapsulates raw data for a user or an option item related to managing users on the device.
- */
+/** Encapsulates raw data for a user or an option item related to managing users on the device. */
 data class UserRecord(
     /** Relevant user information. If `null`, this record is not a user but an option item. */
-    @JvmField
-    val info: UserInfo?,
+    @JvmField val info: UserInfo? = null,
     /** An image representing the user. */
-    @JvmField
-    val picture: Bitmap?,
+    @JvmField val picture: Bitmap? = null,
     /** Whether this record represents an option to switch to a guest user. */
-    @JvmField
-    val isGuest: Boolean,
+    @JvmField val isGuest: Boolean = false,
     /** Whether this record represents the currently-selected user. */
-    @JvmField
-    val isCurrent: Boolean,
+    @JvmField val isCurrent: Boolean = false,
     /** Whether this record represents an option to add another user to the device. */
-    @JvmField
-    val isAddUser: Boolean,
-    /** If true, the record is only visible to the owner and only when unlocked.  */
-    @JvmField
-    val isRestricted: Boolean,
-    /** Whether it is possible to switch to this user. */
-    @JvmField
-    val isSwitchToEnabled: Boolean,
-    /** Whether this record represents an option to add another supervised user to the device. */
-    @JvmField
-    val isAddSupervisedUser: Boolean,
-) {
+    @JvmField val isAddUser: Boolean = false,
     /**
-     * Returns a new instance of [UserRecord] with its [isCurrent] set to the given value.
+     * If true, the record is only available if unlocked or if the user has granted permission to
+     * access this user action whilst on the device is locked.
      */
+    @JvmField val isRestricted: Boolean = false,
+    /** Whether it is possible to switch to this user. */
+    @JvmField val isSwitchToEnabled: Boolean = false,
+    /** Whether this record represents an option to add another supervised user to the device. */
+    @JvmField val isAddSupervisedUser: Boolean = false,
+) {
+    /** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */
     fun copyWithIsCurrent(isCurrent: Boolean): UserRecord {
         return copy(isCurrent = isCurrent)
     }
@@ -67,4 +58,11 @@
             info.id
         }
     }
+
+    companion object {
+        @JvmStatic
+        fun createForGuest(): UserRecord {
+            return UserRecord(isGuest = true)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
new file mode 100644
index 0000000..3c5b969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Encapsulates business logic to interact with user data and systems. */
+@SysUISingleton
+class UserInteractor
+@Inject
+constructor(
+    repository: UserRepository,
+    private val controller: UserSwitcherController,
+    private val activityStarter: ActivityStarter,
+    keyguardInteractor: KeyguardInteractor,
+) {
+    /** List of current on-device users to select from. */
+    val users: Flow<List<UserModel>> = repository.users
+
+    /** The currently-selected user. */
+    val selectedUser: Flow<UserModel> = repository.selectedUser
+
+    /** List of user-switcher related actions that are available. */
+    val actions: Flow<List<UserActionModel>> =
+        combine(
+                repository.isActionableWhenLocked,
+                keyguardInteractor.isKeyguardShowing,
+            ) { isActionableWhenLocked, isLocked ->
+                isActionableWhenLocked || !isLocked
+            }
+            .flatMapLatest { isActionable ->
+                if (isActionable) {
+                    repository.actions.map { actions ->
+                        actions +
+                            if (actions.isNotEmpty()) {
+                                // If we have actions, we add NAVIGATE_TO_USER_MANAGEMENT because
+                                // that's a user
+                                // switcher specific action that is not known to the our data source
+                                // or other
+                                // features.
+                                listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
+                            } else {
+                                // If no actions, don't add the navigate action.
+                                emptyList()
+                            }
+                    }
+                } else {
+                    // If not actionable it means that we're not allowed to show actions when locked
+                    // and we
+                    // are locked. Therefore, we should show no actions.
+                    flowOf(emptyList())
+                }
+            }
+
+    /** Whether the device is configured to always have a guest user available. */
+    val isGuestUserAutoCreated: Boolean = repository.isGuestUserAutoCreated
+
+    /** Whether the guest user is currently being reset. */
+    val isGuestUserResetting: Boolean = repository.isGuestUserResetting
+
+    /** Switches to the user with the given user ID. */
+    fun selectUser(
+        userId: Int,
+    ) {
+        controller.onUserSelected(userId, /* dialogShower= */ null)
+    }
+
+    /** Executes the given action. */
+    fun executeAction(action: UserActionModel) {
+        when (action) {
+            UserActionModel.ENTER_GUEST_MODE -> controller.createAndSwitchToGuestUser(null)
+            UserActionModel.ADD_USER -> controller.showAddUserDialog(null)
+            UserActionModel.ADD_SUPERVISED_USER -> controller.startSupervisedUserActivity()
+            UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
+                activityStarter.startActivity(
+                    Intent(Settings.ACTION_USER_SETTINGS),
+                    /* dismissShade= */ false,
+                )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
new file mode 100644
index 0000000..18369d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/ui/LegacyUserUiHelper.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.legacyhelper.ui
+
+import android.content.Context
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import com.android.systemui.R
+import com.android.systemui.user.data.source.UserRecord
+import kotlin.math.ceil
+
+/**
+ * Defines utility functions for helping with legacy UI code for users.
+ *
+ * We need these to avoid code duplication between logic inside the UserSwitcherController and in
+ * modern architecture classes such as repositories, interactors, and view-models. If we ever
+ * simplify UserSwitcherController (or delete it), the code here could be moved into its call-sites.
+ */
+object LegacyUserUiHelper {
+
+    /** Returns the maximum number of columns for user items in the user switcher. */
+    fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
+        // TODO(b/243844097): remove this once we remove the old user switcher implementation.
+        return if (userCount < 5) {
+            4
+        } else {
+            ceil(userCount / 2.0).toInt()
+        }
+    }
+
+    @JvmStatic
+    @DrawableRes
+    fun getUserSwitcherActionIconResourceId(
+        isAddUser: Boolean,
+        isGuest: Boolean,
+        isAddSupervisedUser: Boolean,
+    ): Int {
+        return if (isAddUser) {
+            R.drawable.ic_add
+        } else if (isGuest) {
+            R.drawable.ic_account_circle
+        } else if (isAddSupervisedUser) {
+            R.drawable.ic_add_supervised_user
+        } else {
+            R.drawable.ic_avatar_user
+        }
+    }
+
+    @JvmStatic
+    fun getUserRecordName(
+        context: Context,
+        record: UserRecord,
+        isGuestUserAutoCreated: Boolean,
+        isGuestUserResetting: Boolean,
+    ): String {
+        val resourceId: Int? = getGuestUserRecordNameResourceId(record)
+        return when {
+            resourceId != null -> context.getString(resourceId)
+            record.info != null -> record.info.name
+            else ->
+                context.getString(
+                    getUserSwitcherActionTextResourceId(
+                        isGuest = record.isGuest,
+                        isGuestUserAutoCreated = isGuestUserAutoCreated,
+                        isGuestUserResetting = isGuestUserResetting,
+                        isAddUser = record.isAddUser,
+                        isAddSupervisedUser = record.isAddSupervisedUser,
+                    )
+                )
+        }
+    }
+
+    /**
+     * Returns the resource ID for a string for the name of the guest user.
+     *
+     * If the given record is not the guest user, returns `null`.
+     */
+    @StringRes
+    fun getGuestUserRecordNameResourceId(record: UserRecord): Int? {
+        return when {
+            record.isGuest && record.isCurrent ->
+                com.android.settingslib.R.string.guest_exit_quick_settings_button
+            record.isGuest && record.info != null -> com.android.internal.R.string.guest_name
+            else -> null
+        }
+    }
+
+    @JvmStatic
+    @StringRes
+    fun getUserSwitcherActionTextResourceId(
+        isGuest: Boolean,
+        isGuestUserAutoCreated: Boolean,
+        isGuestUserResetting: Boolean,
+        isAddUser: Boolean,
+        isAddSupervisedUser: Boolean,
+    ): Int {
+        check(isGuest || isAddUser || isAddSupervisedUser)
+
+        return when {
+            isGuest && isGuestUserAutoCreated && isGuestUserResetting ->
+                com.android.settingslib.R.string.guest_resetting
+            isGuest && isGuestUserAutoCreated -> com.android.internal.R.string.guest_name
+            isGuest -> com.android.internal.R.string.guest_name
+            isAddUser -> com.android.settingslib.R.string.user_add_user
+            isAddSupervisedUser -> R.string.add_user_supervised
+            else -> error("This should never happen!")
+        }
+    }
+
+    /** Alpha value to apply to a user view in the user switcher when it's selectable. */
+    const val USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA = 1.0f
+
+    /** Alpha value to apply to a user view in the user switcher when it's not selectable. */
+    const val USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA = 0.38f
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
copy to packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
index 1de740a..823bf74 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,17 +12,14 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.user.shared.model
 
-import android.annotation.UserIdInt;
-import android.content.Context;
-
-public class ContextUtils {
-
-    /** Get the user associated with this context */
-    public static @UserIdInt int getUserId(Context context) {
-        return context.getUserId();
-    }
+enum class UserActionModel {
+    ENTER_GUEST_MODE,
+    ADD_USER,
+    ADD_SUPERVISED_USER,
+    NAVIGATE_TO_USER_MANAGEMENT,
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt
new file mode 100644
index 0000000..bf7977a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.shared.model
+
+import android.graphics.drawable.Drawable
+import com.android.systemui.common.shared.model.Text
+
+/** Represents a single user on the device. */
+data class UserModel(
+    /** ID of the user, unique across all users on this device. */
+    val id: Int,
+    /** Human-facing name for this user. */
+    val name: Text,
+    /** Human-facing image for this user. */
+    val image: Drawable,
+    /** Whether this user is the currently-selected user. */
+    val isSelected: Boolean,
+    /** Whether this use is selectable. A non-selectable user cannot be switched to. */
+    val isSelectable: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
new file mode 100644
index 0000000..83a3d0d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.binder
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.constraintlayout.helper.widget.Flow as FlowWidget
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Gefingerpoken
+import com.android.systemui.R
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.user.UserSwitcherPopupMenu
+import com.android.systemui.user.UserSwitcherRootView
+import com.android.systemui.user.ui.viewmodel.UserActionViewModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.children
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.launch
+
+/** Binds a user switcher to its view-model. */
+object UserSwitcherViewBinder {
+
+    private const val USER_VIEW_TAG = "user_view"
+
+    /** Binds the given view to the given view-model. */
+    fun bind(
+        view: ViewGroup,
+        viewModel: UserSwitcherViewModel,
+        lifecycleOwner: LifecycleOwner,
+        layoutInflater: LayoutInflater,
+        falsingCollector: FalsingCollector,
+        onFinish: () -> Unit,
+    ) {
+        val rootView: UserSwitcherRootView = view.requireViewById(R.id.user_switcher_root)
+        val flowWidget: FlowWidget = view.requireViewById(R.id.flow)
+        val addButton: View = view.requireViewById(R.id.add)
+        val cancelButton: View = view.requireViewById(R.id.cancel)
+        val popupMenuAdapter = MenuAdapter(layoutInflater)
+        var popupMenu: UserSwitcherPopupMenu? = null
+
+        rootView.touchHandler =
+            object : Gefingerpoken {
+                override fun onTouchEvent(ev: MotionEvent?): Boolean {
+                    falsingCollector.onTouchEvent(ev)
+                    return false
+                }
+            }
+        addButton.setOnClickListener { viewModel.onOpenMenuButtonClicked() }
+        cancelButton.setOnClickListener { viewModel.onCancelButtonClicked() }
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) {
+                launch {
+                    viewModel.isFinishRequested
+                        .filter { it }
+                        .collect {
+                            onFinish()
+                            viewModel.onFinished()
+                        }
+                }
+            }
+        }
+
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.isOpenMenuButtonVisible.collect { addButton.isVisible = it } }
+
+                launch {
+                    viewModel.isMenuVisible.collect { isVisible ->
+                        if (isVisible && popupMenu?.isShowing != true) {
+                            popupMenu?.dismiss()
+                            // Use post to make sure we show the popup menu *after* the activity is
+                            // ready to show one to avoid a WindowManager$BadTokenException.
+                            view.post {
+                                popupMenu =
+                                    createAndShowPopupMenu(
+                                        context = view.context,
+                                        anchorView = addButton,
+                                        adapter = popupMenuAdapter,
+                                        onDismissed = viewModel::onMenuClosed,
+                                    )
+                            }
+                        } else if (!isVisible && popupMenu?.isShowing == true) {
+                            popupMenu?.dismiss()
+                            popupMenu = null
+                        }
+                    }
+                }
+
+                launch {
+                    viewModel.menu.collect { menuViewModels ->
+                        popupMenuAdapter.setItems(menuViewModels)
+                    }
+                }
+
+                launch {
+                    viewModel.maximumUserColumns.collect { maximumColumns ->
+                        flowWidget.setMaxElementsWrap(maximumColumns)
+                    }
+                }
+
+                launch {
+                    viewModel.users.collect { users ->
+                        val viewPool =
+                            view.children.filter { it.tag == USER_VIEW_TAG }.toMutableList()
+                        viewPool.forEach { view.removeView(it) }
+                        users.forEach { userViewModel ->
+                            val userView =
+                                if (viewPool.isNotEmpty()) {
+                                    viewPool.removeAt(0)
+                                } else {
+                                    val inflatedView =
+                                        layoutInflater.inflate(
+                                            R.layout.user_switcher_fullscreen_item,
+                                            view,
+                                            false,
+                                        )
+                                    inflatedView.tag = USER_VIEW_TAG
+                                    inflatedView
+                                }
+                            userView.id = View.generateViewId()
+                            view.addView(userView)
+                            flowWidget.addView(userView)
+                            UserViewBinder.bind(
+                                view = userView,
+                                viewModel = userViewModel,
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun createAndShowPopupMenu(
+        context: Context,
+        anchorView: View,
+        adapter: MenuAdapter,
+        onDismissed: () -> Unit,
+    ): UserSwitcherPopupMenu {
+        return UserSwitcherPopupMenu(context).apply {
+            this.anchorView = anchorView
+            setAdapter(adapter)
+            setOnDismissListener { onDismissed() }
+            setOnItemClickListener { _, _, position, _ ->
+                val itemPositionExcludingHeader = position - 1
+                adapter.getItem(itemPositionExcludingHeader).onClicked()
+            }
+
+            show()
+        }
+    }
+
+    /** Adapter for the menu that can be opened. */
+    private class MenuAdapter(
+        private val layoutInflater: LayoutInflater,
+    ) : BaseAdapter() {
+
+        private val items = mutableListOf<UserActionViewModel>()
+
+        override fun getCount(): Int {
+            return items.size
+        }
+
+        override fun getItem(position: Int): UserActionViewModel {
+            return items[position]
+        }
+
+        override fun getItemId(position: Int): Long {
+            return getItem(position).viewKey
+        }
+
+        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+            val view =
+                convertView
+                    ?: layoutInflater.inflate(
+                        R.layout.user_switcher_fullscreen_popup_item,
+                        parent,
+                        false
+                    )
+            val viewModel = getItem(position)
+            view.requireViewById<ImageView>(R.id.icon).setImageResource(viewModel.iconResourceId)
+            view.requireViewById<TextView>(R.id.text).text =
+                view.resources.getString(viewModel.textResourceId)
+            return view
+        }
+
+        fun setItems(items: List<UserActionViewModel>) {
+            this.items.clear()
+            this.items.addAll(items)
+            notifyDataSetChanged()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt
new file mode 100644
index 0000000..e78807e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.binder
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.LayerDrawable
+import android.view.View
+import android.widget.ImageView
+import androidx.core.content.res.ResourcesCompat
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.common.ui.binder.TextViewBinder
+import com.android.systemui.user.ui.viewmodel.UserViewModel
+
+/** Binds a user view to its view-model. */
+object UserViewBinder {
+    /** Binds the given view to the given view-model. */
+    fun bind(view: View, viewModel: UserViewModel) {
+        TextViewBinder.bind(view.requireViewById(R.id.user_switcher_text), viewModel.name)
+        view
+            .requireViewById<ImageView>(R.id.user_switcher_icon)
+            .setImageDrawable(getSelectableDrawable(view.context, viewModel))
+        view.alpha = viewModel.alpha
+        if (viewModel.onClicked != null) {
+            view.setOnClickListener { viewModel.onClicked.invoke() }
+        } else {
+            view.setOnClickListener(null)
+        }
+    }
+
+    private fun getSelectableDrawable(context: Context, viewModel: UserViewModel): Drawable {
+        val layerDrawable =
+            checkNotNull(
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.user_switcher_icon_large,
+                        context.theme,
+                    )
+                )
+                .mutate() as LayerDrawable
+        if (viewModel.isSelectionMarkerVisible) {
+            (layerDrawable.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
+                val stroke =
+                    context.resources.getDimensionPixelSize(
+                        R.dimen.user_switcher_icon_selected_width
+                    )
+                val color =
+                    Utils.getColorAttrDefaultColor(
+                        context,
+                        com.android.internal.R.attr.colorAccentPrimary
+                    )
+
+                setStroke(stroke, color)
+            }
+        }
+
+        layerDrawable.setDrawableByLayerId(R.id.user_avatar, viewModel.image)
+        return layerDrawable
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserActionViewModel.kt
new file mode 100644
index 0000000..149b1ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserActionViewModel.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.viewmodel
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+
+/** Models UI state for an action that can be performed on a user. */
+data class UserActionViewModel(
+    /**
+     * Key to use with the view or compose system to keep track of the view/composable across
+     * changes to the collection of [UserActionViewModel] instances.
+     */
+    val viewKey: Long,
+    @DrawableRes val iconResourceId: Int,
+    @StringRes val textResourceId: Int,
+    val onClicked: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
new file mode 100644
index 0000000..398341d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.R
+import com.android.systemui.common.ui.drawable.CircularDrawable
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+
+/** Models UI state for the user switcher feature. */
+class UserSwitcherViewModel
+private constructor(
+    private val userInteractor: UserInteractor,
+    private val powerInteractor: PowerInteractor,
+) : ViewModel() {
+
+    /** On-device users. */
+    val users: Flow<List<UserViewModel>> =
+        userInteractor.users.map { models -> models.map { user -> toViewModel(user) } }
+
+    /** The maximum number of columns that the user selection grid should use. */
+    val maximumUserColumns: Flow<Int> =
+        users.map { LegacyUserUiHelper.getMaxUserSwitcherItemColumns(it.size) }
+
+    /** Whether the button to open the user action menu is visible. */
+    val isOpenMenuButtonVisible: Flow<Boolean> = userInteractor.actions.map { it.isNotEmpty() }
+
+    private val _isMenuVisible = MutableStateFlow(false)
+    /**
+     * Whether the user action menu should be shown. Once the action menu is dismissed/closed, the
+     * consumer must invoke [onMenuClosed].
+     */
+    val isMenuVisible: Flow<Boolean> = _isMenuVisible
+    /** The user action menu. */
+    val menu: Flow<List<UserActionViewModel>> =
+        userInteractor.actions.map { actions -> actions.map { action -> toViewModel(action) } }
+
+    private val hasCancelButtonBeenClicked = MutableStateFlow(false)
+
+    /**
+     * Whether the observer should finish the experience. Once consumed, [onFinished] must be called
+     * by the consumer.
+     */
+    val isFinishRequested: Flow<Boolean> = createFinishRequestedFlow()
+
+    /** Notifies that the user has clicked the cancel button. */
+    fun onCancelButtonClicked() {
+        hasCancelButtonBeenClicked.value = true
+    }
+
+    /**
+     * Notifies that the user experience is finished.
+     *
+     * Call this after consuming [isFinishRequested] with a `true` value in order to mark it as
+     * consumed such that the next consumer doesn't immediately finish itself.
+     */
+    fun onFinished() {
+        hasCancelButtonBeenClicked.value = false
+    }
+
+    /** Notifies that the user has clicked the "open menu" button. */
+    fun onOpenMenuButtonClicked() {
+        _isMenuVisible.value = true
+    }
+
+    /**
+     * Notifies that the user has dismissed or closed the user action menu.
+     *
+     * Call this after consuming [isMenuVisible] with a `true` value in order to reset it to `false`
+     * such that the next consumer doesn't immediately show the menu again.
+     */
+    fun onMenuClosed() {
+        _isMenuVisible.value = false
+    }
+
+    private fun createFinishRequestedFlow(): Flow<Boolean> {
+        var mostRecentSelectedUserId: Int? = null
+        var mostRecentIsInteractive: Boolean? = null
+
+        return combine(
+            // When the user is switched, we should finish.
+            userInteractor.selectedUser
+                .map { it.id }
+                .map {
+                    val selectedUserChanged =
+                        mostRecentSelectedUserId != null && mostRecentSelectedUserId != it
+                    mostRecentSelectedUserId = it
+                    selectedUserChanged
+                },
+            // When the screen turns off, we should finish.
+            powerInteractor.isInteractive.map {
+                val screenTurnedOff = mostRecentIsInteractive == true && !it
+                mostRecentIsInteractive = it
+                screenTurnedOff
+            },
+            // When the cancel button is clicked, we should finish.
+            hasCancelButtonBeenClicked,
+        ) { selectedUserChanged, screenTurnedOff, cancelButtonClicked ->
+            selectedUserChanged || screenTurnedOff || cancelButtonClicked
+        }
+    }
+
+    private fun toViewModel(
+        model: UserModel,
+    ): UserViewModel {
+        return UserViewModel(
+            viewKey = model.id,
+            name = model.name,
+            image = CircularDrawable(model.image),
+            isSelectionMarkerVisible = model.isSelected,
+            alpha =
+                if (model.isSelectable) {
+                    LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA
+                } else {
+                    LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA
+                },
+            onClicked = createOnSelectedCallback(model),
+        )
+    }
+
+    private fun toViewModel(
+        model: UserActionModel,
+    ): UserActionViewModel {
+        return UserActionViewModel(
+            viewKey = model.ordinal.toLong(),
+            iconResourceId =
+                if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+                    R.drawable.ic_manage_users
+                } else {
+                    LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
+                        isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+                        isAddUser = model == UserActionModel.ADD_USER,
+                        isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+                    )
+                },
+            textResourceId =
+                if (model == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+                    R.string.manage_users
+                } else {
+                    LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
+                        isGuest = model == UserActionModel.ENTER_GUEST_MODE,
+                        isGuestUserAutoCreated = userInteractor.isGuestUserAutoCreated,
+                        isGuestUserResetting = userInteractor.isGuestUserResetting,
+                        isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
+                        isAddUser = model == UserActionModel.ADD_USER,
+                    )
+                },
+            onClicked = { userInteractor.executeAction(action = model) },
+        )
+    }
+
+    private fun createOnSelectedCallback(model: UserModel): (() -> Unit)? {
+        return if (!model.isSelectable) {
+            null
+        } else {
+            { userInteractor.selectUser(model.id) }
+        }
+    }
+
+    class Factory
+    @Inject
+    constructor(
+        private val userInteractor: UserInteractor,
+        private val powerInteractor: PowerInteractor,
+    ) : ViewModelProvider.Factory {
+        override fun <T : ViewModel> create(modelClass: Class<T>): T {
+            @Suppress("UNCHECKED_CAST")
+            return UserSwitcherViewModel(
+                userInteractor = userInteractor,
+                powerInteractor = powerInteractor,
+            )
+                as T
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserViewModel.kt
new file mode 100644
index 0000000..d57bba0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserViewModel.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+import com.android.systemui.common.shared.model.Text
+
+/** Models UI state for representing a single user. */
+data class UserViewModel(
+    /**
+     * Key to use with the view or compose system to keep track of the view/composable across
+     * changes to the collection of [UserViewModel] instances.
+     */
+    val viewKey: Int,
+    val name: Text,
+    val image: Drawable,
+    /** Whether a marker should be shown to highlight that this user is the selected one. */
+    val isSelectionMarkerVisible: Boolean,
+    val alpha: Float,
+    val onClicked: (() -> Unit)?,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index 7baebf4..f71d596 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -16,11 +16,15 @@
 
 package com.android.systemui.util.kotlin
 
+import java.util.concurrent.atomic.AtomicReference
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.drop
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.zip
+import kotlinx.coroutines.launch
 
 /**
  * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
@@ -29,15 +33,16 @@
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
-fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> {
-    // same as current flow, but with the very first event skipped
-    val nextEvents = drop(1)
-    // zip current flow and nextEvents; transform will receive a pair of old and new value. This
-    // works because zip will suppress emissions until both flows have emitted something; since in
-    // this case both flows are emitting at the same rate, but the current flow just has one extra
-    // thing emitted at the start, the effect is that zip will cache the most recent value while
-    // waiting for the next emission from nextEvents.
-    return zip(nextEvents, transform)
+fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> = flow {
+    val noVal = Any()
+    var previousValue: Any? = noVal
+    collect { newVal ->
+        if (previousValue != noVal) {
+            @Suppress("UNCHECKED_CAST")
+            emit(transform(previousValue as T, newVal))
+        }
+        previousValue = newVal
+    }
 }
 
 /**
@@ -74,10 +79,19 @@
 /**
  * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using
  * [transform].
+ *
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
+ * a change event to be emitted that contains no removals, and all elements from that first [Set]
+ * as additions.
+ *
+ * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
+ * until a second [Set] has been emitted from the upstream [Flow].
  */
 fun <T, R> Flow<Set<T>>.setChangesBy(
     transform: suspend (removed: Set<T>, added: Set<T>) -> R,
-): Flow<R> = onStart { emit(emptySet()) }.distinctUntilChanged()
+    emitFirstEvent: Boolean = true,
+): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this)
+    .distinctUntilChanged()
     .pairwiseBy { old: Set<T>, new: Set<T> ->
         // If an element was present in the old set, but not the new one, then it was removed
         val removed = old - new
@@ -86,8 +100,18 @@
         transform(removed, added)
     }
 
-/** Returns a new [Flow] that produces the [Set] changes between each emission from [this]. */
-fun <T> Flow<Set<T>>.setChanges(): Flow<SetChanges<T>> = setChangesBy(::SetChanges)
+/**
+ * Returns a new [Flow] that produces the [Set] changes between each emission from [this].
+ *
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
+ * a change event to be emitted that contains no removals, and all elements from that first [Set]
+ * as additions.
+ *
+ * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
+ * until a second [Set] has been emitted from the upstream [Flow].
+ */
+fun <T> Flow<Set<T>>.setChanges(emitFirstEvent: Boolean = true): Flow<SetChanges<T>> =
+    setChangesBy(::SetChanges, emitFirstEvent)
 
 /** Contains the difference in elements between two [Set]s. */
 data class SetChanges<T>(
@@ -96,3 +120,35 @@
     /** Elements that are present in the second [Set] but not in the first. */
     val added: Set<T>,
 )
+
+/**
+ * Returns a new [Flow] that emits at the same rate as [this], but combines the emitted value with
+ * the most recent emission from [other] using [transform].
+ *
+ * Note that the returned Flow will not emit anything until [other] has emitted at least one value.
+ */
+fun <A, B, C> Flow<A>.sample(other: Flow<B>, transform: suspend (A, B) -> C): Flow<C> = flow {
+    coroutineScope {
+        val noVal = Any()
+        val sampledRef = AtomicReference(noVal)
+        val job = launch(Dispatchers.Unconfined) {
+            other.collect { sampledRef.set(it) }
+        }
+        collect {
+            val sampled = sampledRef.get()
+            if (sampled != noVal) {
+                @Suppress("UNCHECKED_CAST")
+                emit(transform(it, sampled as B))
+            }
+        }
+        job.cancel()
+    }
+}
+
+/**
+ * Returns a new [Flow] that emits at the same rate as [this], but emits the most recently emitted
+ * value from [other] instead.
+ *
+ * Note that the returned Flow will not emit anything until [other] has emitted at least one value.
+ */
+fun <A> Flow<*>.sample(other: Flow<A>): Flow<A> = sample(other) { _, a -> a }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt
new file mode 100644
index 0000000..2e551f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Runs the given [blocks] in parallel, returning the result of the first one to complete, and
+ * cancelling all others.
+ */
+suspend fun <R> race(vararg blocks: suspend () -> R): R = coroutineScope {
+    val completion = CompletableDeferred<R>()
+    val raceJob = launch {
+        for (block in blocks) {
+            launch { completion.complete(block()) }
+        }
+    }
+    completion.await().also { raceJob.cancel() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
index 2c74fb9..87a167b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
@@ -52,6 +52,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.settingslib.media.MediaOutputConstants;
 import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.util.ArrayList;
@@ -69,6 +70,7 @@
     private static final int DURATION_SLICE_BINDING_TIMEOUT_MS = 200;
     private static final int DEFAULT_SLICE_SIZE = 4;
 
+    private final ActivityStarter mActivityStarter;
     private RecyclerView mVolumePanelSlices;
     private VolumePanelSlicesAdapter mVolumePanelSlicesAdapter;
     private final LifecycleRegistry mLifecycleRegistry;
@@ -78,8 +80,10 @@
     private boolean mSlicesReadyToLoad;
     private LocalBluetoothProfileManager mProfileManager;
 
-    public VolumePanelDialog(Context context, boolean aboveStatusBar) {
+    public VolumePanelDialog(Context context,
+            ActivityStarter activityStarter, boolean aboveStatusBar) {
         super(context);
+        mActivityStarter = activityStarter;
         mLifecycleRegistry = new LifecycleRegistry(this);
         if (!aboveStatusBar) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -100,9 +104,11 @@
         doneButton.setOnClickListener(v -> dismiss());
         Button settingsButton = dialogView.findViewById(R.id.settings_button);
         settingsButton.setOnClickListener(v -> {
-            getContext().startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS).addFlags(
-                    Intent.FLAG_ACTIVITY_NEW_TASK));
             dismiss();
+
+            Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mActivityStarter.startActivity(intent, /* dismissShade= */ true);
         });
 
         LocalBluetoothManager localBluetoothManager = LocalBluetoothManager.getInstance(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
index c2fafbf..0debe0e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
@@ -21,6 +21,7 @@
 import android.view.View
 import com.android.systemui.animation.DialogLaunchAnimator
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.ActivityStarter
 import javax.inject.Inject
 
 private const val TAG = "VolumePanelFactory"
@@ -33,6 +34,7 @@
 @SysUISingleton
 class VolumePanelFactory @Inject constructor(
     private val context: Context,
+    private val activityStarter: ActivityStarter,
     private val dialogLaunchAnimator: DialogLaunchAnimator
 ) {
     companion object {
@@ -45,7 +47,7 @@
             return
         }
 
-        val dialog = VolumePanelDialog(context, aboveStatusBar)
+        val dialog = VolumePanelDialog(context, activityStarter, aboveStatusBar)
         volumePanelDialog = dialog
 
         // Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 8ff90f7..2878ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui;
+package com.android.systemui.wallpapers;
 
 import android.app.WallpaperColors;
 import android.graphics.Bitmap;
@@ -37,8 +37,8 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.glwallpaper.EglHelper;
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.wallpapers.gl.EglHelper;
+import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS b/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS
new file mode 100644
index 0000000..731c798
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+cinek@google.com
+dupin@google.com
+pomini@google.com
+santie@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
index 11e215d..f9ddce8 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/EglHelper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.EGL14.EGL_ALPHA_SIZE;
 import static android.opengl.EGL14.EGL_BLUE_SIZE;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
index 6152490..692ced0 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/GLWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/GLWallpaperRenderer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import android.util.Size;
 
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
index d03b00b..d34eca4 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLProgram.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
 import static android.opengl.GLES20.GL_VERTEX_SHADER;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
index 1a53c28..f1659b9 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageGLWallpaper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.GLES20.GL_FLOAT;
 import static android.opengl.GLES20.GL_LINEAR;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
rename to packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
index 7c0b93b..e393786 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/gl/ImageWallpaperRenderer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
 import static android.opengl.GLES20.glClear;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 8c41374..4e77514 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -311,18 +311,6 @@
             }
 
             @Override
-            public void notifyMaybeCancelSummary(String key) {
-                sysuiMainExecutor.execute(() -> {
-                    final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
-                    if (entry != null) {
-                        for (NotifCallback cb : mCallbacks) {
-                            cb.maybeCancelSummary(entry);
-                        }
-                    }
-                });
-            }
-
-            @Override
             public void updateNotificationBubbleButton(String key) {
                 sysuiMainExecutor.execute(() -> {
                     final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
@@ -646,15 +634,5 @@
          * filtered from the shade.
          */
         void invalidateNotifications(@NonNull String reason);
-
-        /**
-         * Called on a bubbled entry that has been removed when there are no longer
-         * bubbled entries in its group.
-         *
-         * Checks whether its group has any other (non-bubbled) children. If it doesn't,
-         * removes all remnants of the group's summary from the notification pipeline.
-         * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
-         */
-        void maybeCancelSummary(@NonNull NotificationEntry entry);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
similarity index 90%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
index 013c298..0a9c745 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
@@ -33,14 +33,14 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
-public class KeyguardMessageAreaTest extends SysuiTestCase {
+public class AuthKeyguardMessageAreaTest extends SysuiTestCase {
     private KeyguardMessageArea mKeyguardMessageArea;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
-        mKeyguardMessageArea.setBouncerShowing(true);
+        mKeyguardMessageArea = new AuthKeyguardMessageArea(mContext, null);
+        mKeyguardMessageArea.setIsVisible(true);
     }
 
     @Test
@@ -53,7 +53,7 @@
 
     @Test
     public void testHiddenWhenBouncerHidden() {
-        mKeyguardMessageArea.setBouncerShowing(false);
+        mKeyguardMessageArea.setIsVisible(false);
         mKeyguardMessageArea.setVisibility(View.INVISIBLE);
         mKeyguardMessageArea.setMessage("oobleck");
         assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index 90f7fda..8bbaf3d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -56,7 +56,7 @@
     @Mock
     private PasswordTextView mPasswordEntry;
     @Mock
-    private KeyguardMessageArea mKeyguardMessageArea;
+    private BouncerKeyguardMessageArea mKeyguardMessageArea;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
@@ -85,7 +85,7 @@
         when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1);
         when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry);
         when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true);
-        when(mAbsKeyInputView.findViewById(R.id.keyguard_message_area))
+        when(mAbsKeyInputView.requireViewById(R.id.bouncer_message_area))
                 .thenReturn(mKeyguardMessageArea);
         mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
                 mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
index 0bf038d..2714cf4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -90,6 +90,8 @@
     onlyFaceEnrolled = false,
     faceAuthenticated = false,
     faceDisabled = false,
+    faceLockedOut = false,
+    fpLockedOut = false,
     goingToSleep = false,
     keyguardAwakeExcludingBouncerShowing = false,
     keyguardGoingAway = false,
@@ -99,5 +101,5 @@
     scanningAllowedByStrongAuth = false,
     secureCameraLaunched = false,
     switchingUser = false,
-    udfpsBouncerShowing = false
+    udfpsBouncerShowing = false,
 )
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index 8293cc2..69524e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -89,8 +89,8 @@
 
     @Test
     public void testSetBouncerVisible() {
-        mMessageAreaController.setBouncerShowing(true);
-        verify(mKeyguardMessageArea).setBouncerShowing(true);
+        mMessageAreaController.setIsVisible(true);
+        verify(mKeyguardMessageArea).setIsVisible(true);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index ec85603..b89dbd9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -64,9 +64,10 @@
     @Mock
     lateinit var keyguardViewController: KeyguardViewController
     @Mock
-    private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+    private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
     @Mock
-    private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+    private lateinit var mKeyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
 
     private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
 
@@ -74,7 +75,8 @@
     fun setup() {
         MockitoAnnotations.initMocks(this)
         Mockito.`when`(
-            keyguardPasswordView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area)
+            keyguardPasswordView
+                .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area)
         ).thenReturn(mKeyguardMessageArea)
         Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
             .thenReturn(mKeyguardMessageAreaController)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 616a105..3262a77 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -66,10 +66,11 @@
     var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
 
     @Mock
-    private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+    private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
 
     @Mock
-    private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+    private lateinit var mKeyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
 
     @Mock
     private lateinit var mLockPatternView: LockPatternView
@@ -83,7 +84,8 @@
     fun setup() {
         MockitoAnnotations.initMocks(this)
         `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
-        `when`(mKeyguardPatternView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area))
+        `when`(mKeyguardPatternView
+            .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area))
             .thenReturn(mKeyguardMessageArea)
         `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
             .thenReturn(mLockPatternView)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 7bc8e8a..97d556b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -51,7 +51,7 @@
     @Mock
     private PasswordTextView mPasswordEntry;
     @Mock
-    private KeyguardMessageArea mKeyguardMessageArea;
+    private BouncerKeyguardMessageArea mKeyguardMessageArea;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
@@ -90,7 +90,7 @@
         when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
         when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
         when(mPinBasedInputView.getButtons()).thenReturn(mButtons);
-        when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
+        when(mPinBasedInputView.requireViewById(R.id.bouncer_message_area))
                 .thenReturn(mKeyguardMessageArea);
         when(mPinBasedInputView.findViewById(R.id.delete_button))
                 .thenReturn(mDeleteButton);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
new file mode 100644
index 0000000..9e5bfe5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.util.LatencyTracker
+import com.android.internal.widget.LockPatternUtils
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.statusbar.policy.DevicePostureController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardPinViewControllerTest : SysuiTestCase() {
+    @Mock private lateinit var keyguardPinView: KeyguardPINView
+
+    @Mock private lateinit var keyguardMessageArea: BouncerKeyguardMessageArea
+
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+
+    @Mock private lateinit var securityMode: SecurityMode
+
+    @Mock private lateinit var lockPatternUtils: LockPatternUtils
+
+    @Mock private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
+
+    @Mock
+    private lateinit var keyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
+
+    @Mock
+    private lateinit var keyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
+
+    @Mock private lateinit var mLatencyTracker: LatencyTracker
+
+    @Mock private lateinit var liftToActivateListener: LiftToActivateListener
+
+    @Mock private val mEmergencyButtonController: EmergencyButtonController? = null
+    private val falsingCollector: FalsingCollector = FalsingCollectorFake()
+    @Mock lateinit var postureController: DevicePostureController
+
+    lateinit var pinViewController: KeyguardPinViewController
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        Mockito.`when`(keyguardPinView.requireViewById<View>(R.id.bouncer_message_area))
+            .thenReturn(keyguardMessageArea)
+        Mockito.`when`(
+                keyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea::class.java))
+            )
+            .thenReturn(keyguardMessageAreaController)
+        pinViewController =
+            KeyguardPinViewController(
+                keyguardPinView,
+                keyguardUpdateMonitor,
+                securityMode,
+                lockPatternUtils,
+                mKeyguardSecurityCallback,
+                keyguardMessageAreaControllerFactory,
+                mLatencyTracker,
+                liftToActivateListener,
+                mEmergencyButtonController,
+                falsingCollector,
+                postureController
+            )
+    }
+
+    @Test
+    fun startAppearAnimation() {
+        pinViewController.startAppearAnimation()
+        verify(keyguardMessageAreaController).setMessageIfEmpty(R.string.keyguard_enter_your_pin)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index d68e8bd..c6ebaa8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -41,6 +41,7 @@
 import android.hardware.biometrics.BiometricSourceType;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowInsetsController;
@@ -117,7 +118,7 @@
     @Mock
     private KeyguardMessageAreaController mKeyguardMessageAreaController;
     @Mock
-    private KeyguardMessageArea mKeyguardMessageArea;
+    private BouncerKeyguardMessageArea mKeyguardMessageArea;
     @Mock
     private ConfigurationController mConfigurationController;
     @Mock
@@ -163,9 +164,10 @@
         when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
                 .thenReturn(mAdminSecondaryLockScreenController);
         when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
-        mKeyguardPasswordView = spy(new KeyguardPasswordView(getContext()));
+        mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
+                R.layout.keyguard_password_view, null));
         when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
-        when(mKeyguardPasswordView.findViewById(R.id.keyguard_message_area))
+        when(mKeyguardPasswordView.requireViewById(R.id.bouncer_message_area))
                 .thenReturn(mKeyguardMessageArea);
         when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
                 .thenReturn(mKeyguardMessageAreaController);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index fde288f..508f81d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -18,7 +18,9 @@
 
 import static android.app.StatusBarManager.SESSION_KEYGUARD;
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
 import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
 import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
 
@@ -31,6 +33,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
@@ -73,6 +76,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IRemoteCallback;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -198,6 +202,8 @@
     private SessionTracker mSessionTracker;
     @Mock
     private UiEventLogger mUiEventLogger;
+    @Mock
+    private PowerManager mPowerManager;
 
     private final int mCurrentUserId = 100;
     private final UserInfo mCurrentUserInfo = new UserInfo(mCurrentUserId, "Test user", 0);
@@ -746,8 +752,7 @@
         mTestableLooper.processAllMessages();
         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
 
-        mKeyguardUpdateMonitor.mFaceAuthenticationCallback
-                .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+        faceAuthLockedOut();
 
         verify(mLockPatternUtils, never()).requireStrongAuth(anyInt(), anyInt());
     }
@@ -759,7 +764,7 @@
         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
 
         mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
-                .onAuthenticationError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
+                .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
 
         verify(mLockPatternUtils).requireStrongAuth(anyInt(), anyInt());
     }
@@ -770,10 +775,9 @@
         mTestableLooper.processAllMessages();
         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
 
-        mKeyguardUpdateMonitor.mFaceAuthenticationCallback
-                .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+        faceAuthLockedOut();
         mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
-                .onAuthenticationError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
+                .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
 
         verify(mLockPatternUtils).requireStrongAuth(anyInt(), anyInt());
     }
@@ -1212,7 +1216,7 @@
     public void testShouldListenForFace_whenFpIsLockedOut_returnsFalse() throws RemoteException {
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
-        bouncerFullyVisibleAndNotGoingToSleep();
+        occludingAppRequestsFaceAuth();
         currentUserIsPrimary();
         strongAuthNotRequired();
         biometricsEnabledForCurrentUser();
@@ -1220,6 +1224,7 @@
         biometricsNotDisabledThroughDevicePolicyManager();
         userNotCurrentlySwitching();
         mTestableLooper.processAllMessages();
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
 
         // Fingerprint is locked out.
         fingerprintErrorLockedOut();
@@ -1495,6 +1500,27 @@
     }
 
     @Test
+    public void testShouldListenForFace_whenFaceIsLockedOut_returnsFalse()
+            throws RemoteException {
+        // Preconditions for face auth to run
+        keyguardNotGoingAway();
+        currentUserIsPrimary();
+        currentUserDoesNotHaveTrust();
+        biometricsNotDisabledThroughDevicePolicyManager();
+        biometricsEnabledForCurrentUser();
+        userNotCurrentlySwitching();
+        mKeyguardUpdateMonitor.setUdfpsBouncerShowing(true);
+        mTestableLooper.processAllMessages();
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+
+        // Face is locked out.
+        faceAuthLockedOut();
+        mTestableLooper.processAllMessages();
+
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
+    }
+
+    @Test
     public void testBouncerVisibility_whenBothFingerprintAndFaceIsEnrolled_stopsFaceAuth()
             throws RemoteException {
         // Both fingerprint and face are enrolled by default
@@ -1560,6 +1586,33 @@
         assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(anyBoolean())).isEqualTo(true);
     }
 
+    @Test
+    public void testFingerAcquired_wakesUpPowerManager() {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.kg_wake_on_acquire_start, true);
+        mSpiedContext = spy(mContext);
+        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        fingerprintAcquireStart();
+
+        verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
+    }
+
+    @Test
+    public void testFingerAcquired_doesNotWakeUpPowerManager() {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.kg_wake_on_acquire_start, false);
+        mSpiedContext = spy(mContext);
+        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        fingerprintAcquireStart();
+
+        verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+    }
+
+    private void faceAuthLockedOut() {
+        mKeyguardUpdateMonitor.mFaceAuthenticationCallback
+                .onAuthenticationError(FaceManager.FACE_ERROR_LOCKOUT_PERMANENT, "");
+    }
+
     private void faceAuthEnabled() {
         // this ensures KeyguardUpdateMonitor updates the cached mIsFaceEnrolled flag using the
         // face manager mock wire-up in setup()
@@ -1608,6 +1661,11 @@
                 .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
     }
 
+    private void fingerprintAcquireStart() {
+        mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
+                .onAuthenticationAcquired(FINGERPRINT_ACQUIRED_START);
+    }
+
     private void triggerSuccessfulFaceAuth() {
         mKeyguardUpdateMonitor.requestFaceAuth(true, FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
         verify(mFaceManager).authenticate(any(),
@@ -1729,7 +1787,8 @@
                     mStatusBarStateController, mLockPatternUtils,
                     mAuthController, mTelephonyListenerManager,
                     mInteractionJankMonitor, mLatencyTracker, mActiveUnlockConfig,
-                    mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker);
+                    mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
+                    mPowerManager);
             setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index e2790e4..a61cd23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -161,7 +161,18 @@
         runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
 
         waitForIdleSync()
-        verify(controller).onLaunchAnimationCancelled()
+        verify(controller).onLaunchAnimationCancelled(false /* newKeyguardOccludedState */)
+        verify(controller, never()).onLaunchAnimationStart(anyBoolean())
+    }
+
+    @Test
+    fun passesOccludedStateToLaunchAnimationCancelled_ifTrue() {
+        val runner = activityLaunchAnimator.createRunner(controller)
+        runner.onAnimationCancelled(true /* isKeyguardOccluded */)
+        runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
+
+        waitForIdleSync()
+        verify(controller).onLaunchAnimationCancelled(true /* newKeyguardOccludedState */)
         verify(controller, never()).onLaunchAnimationStart(anyBoolean())
     }
 
@@ -253,7 +264,7 @@
         assertOnMainThread()
     }
 
-    override fun onLaunchAnimationCancelled() {
+    override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
         assertOnMainThread()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
new file mode 100644
index 0000000..c9ccdb3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.keyguard.logging.BiometricMessageDeferralLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class FaceHelpMessageDeferralTest : SysuiTestCase() {
+    val threshold = .75f
+    @Mock lateinit var logger: BiometricMessageDeferralLogger
+    @Mock lateinit var dumpManager: DumpManager
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun testProcessFrame_logs() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1))
+        biometricMessageDeferral.processFrame(1)
+        verify(logger).logFrameProcessed(1, 1, "1")
+    }
+
+    @Test
+    fun testUpdateMessage_logs() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1))
+        biometricMessageDeferral.updateMessage(1, "hi")
+        verify(logger).logUpdateMessage(1, "hi")
+    }
+
+    @Test
+    fun testReset_logs() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1))
+        biometricMessageDeferral.reset()
+        verify(logger).reset()
+    }
+
+    @Test
+    fun testProcessNoMessages_noDeferredMessage() {
+        val biometricMessageDeferral = createMsgDeferral(emptySet())
+
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testProcessNonDeferredMessages_noDeferredMessage() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
+
+        // WHEN there are no deferred messages processed
+        for (i in 0..3) {
+            biometricMessageDeferral.processFrame(4)
+            biometricMessageDeferral.updateMessage(4, "test")
+        }
+
+        // THEN getDeferredMessage is null
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testProcessMessagesWithDeferredMessage_deferredMessageWasNeverGivenAString() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
+
+        biometricMessageDeferral.processFrame(1)
+
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testAllProcessedMessagesWereDeferred() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1))
+
+        // WHEN all the processed messages are a deferred message
+        for (i in 0..3) {
+            biometricMessageDeferral.processFrame(1)
+            biometricMessageDeferral.updateMessage(1, "test")
+        }
+
+        // THEN deferredMessage will return the string associated with the deferred msgId
+        assertEquals("test", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testReturnsMostFrequentDeferredMessage() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
+
+        // WHEN there's 80%of the messages are msgId=1 and 20% is msgId=2
+        biometricMessageDeferral.processFrame(1)
+        biometricMessageDeferral.processFrame(1)
+        biometricMessageDeferral.processFrame(1)
+        biometricMessageDeferral.processFrame(1)
+        biometricMessageDeferral.updateMessage(1, "msgId-1")
+
+        biometricMessageDeferral.processFrame(2)
+        biometricMessageDeferral.updateMessage(2, "msgId-2")
+
+        // THEN the most frequent deferred message is that meets the threshold is returned
+        assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testDeferredMessage_mustMeetThreshold() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1))
+
+        // WHEN more nonDeferredMessages are shown than the deferred message
+        val totalMessages = 10
+        val nonDeferredMessagesCount = (totalMessages * threshold).toInt() + 1
+        for (i in 0 until nonDeferredMessagesCount) {
+            biometricMessageDeferral.processFrame(4)
+            biometricMessageDeferral.updateMessage(4, "non-deferred-msg")
+        }
+        for (i in nonDeferredMessagesCount until totalMessages) {
+            biometricMessageDeferral.processFrame(1)
+            biometricMessageDeferral.updateMessage(1, "msgId-1")
+        }
+
+        // THEN there's no deferred message because it didn't meet the threshold
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testResetClearsOutCounts() {
+        val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
+
+        // GIVEN two msgId=1 events processed
+        biometricMessageDeferral.processFrame(
+            1,
+        )
+        biometricMessageDeferral.updateMessage(1, "msgId-1")
+        biometricMessageDeferral.processFrame(1)
+        biometricMessageDeferral.updateMessage(1, "msgId-1")
+
+        // WHEN counts are reset and then a single deferred message is processed (msgId=2)
+        biometricMessageDeferral.reset()
+        biometricMessageDeferral.processFrame(2)
+        biometricMessageDeferral.updateMessage(2, "msgId-2")
+
+        // THEN msgId-2 is the deferred message since the two msgId=1 events were reset
+        assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testShouldDefer() {
+        // GIVEN should defer msgIds 1 and 2
+        val biometricMessageDeferral = createMsgDeferral(setOf(1, 2))
+
+        // THEN shouldDefer returns true for ids 1 & 2
+        assertTrue(biometricMessageDeferral.shouldDefer(1))
+        assertTrue(biometricMessageDeferral.shouldDefer(2))
+
+        // THEN should defer returns false for ids 3 & 4
+        assertFalse(biometricMessageDeferral.shouldDefer(3))
+        assertFalse(biometricMessageDeferral.shouldDefer(4))
+    }
+
+    private fun createMsgDeferral(messagesToDefer: Set<Int>): BiometricMessageDeferral {
+        return BiometricMessageDeferral(messagesToDefer, threshold, logger, dumpManager)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 7f6b79b..4ebae98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -310,7 +310,7 @@
     @Test
     public void testOnViewDetachedRemovesViews() {
         mController.onViewDetached();
-        verify(mView).removeAllStatusBarItemViews();
+        verify(mView).removeAllExtraStatusBarItemViews();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
index a4d2238..a78c902 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -60,7 +60,18 @@
     @Mock
     private lateinit var launcherUnlockAnimationController: ILauncherUnlockAnimationController.Stub
 
-    private lateinit var remoteAnimationTarget: RemoteAnimationTarget
+    private var surfaceControl1 = mock(SurfaceControl::class.java)
+    private var remoteTarget1 = RemoteAnimationTarget(
+            0 /* taskId */, 0, surfaceControl1, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
+            mock(WindowConfiguration::class.java), false, surfaceControl1, Rect(),
+            mock(ActivityManager.RunningTaskInfo::class.java), false)
+
+    private var surfaceControl2 = mock(SurfaceControl::class.java)
+    private var remoteTarget2 = RemoteAnimationTarget(
+            1 /* taskId */, 0, surfaceControl2, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
+            mock(WindowConfiguration::class.java), false, surfaceControl2, Rect(),
+            mock(ActivityManager.RunningTaskInfo::class.java), false)
+    private lateinit var remoteAnimationTargets: Array<RemoteAnimationTarget>
 
     @Before
     fun setUp() {
@@ -77,10 +88,7 @@
 
         // All of these fields are final, so we can't mock them, but are needed so that the surface
         // appear amount setter doesn't short circuit.
-        remoteAnimationTarget = RemoteAnimationTarget(
-            0, 0, null, false, Rect(), Rect(), 0, Point(), Rect(), Rect(),
-            mock(WindowConfiguration::class.java), false, mock(SurfaceControl::class.java), Rect(),
-            mock(ActivityManager.RunningTaskInfo::class.java), false)
+        remoteAnimationTargets = arrayOf(remoteTarget1)
 
         // Set the surface applier to our mock so that we can verify the arguments passed to it.
         // This applier does not have any side effects within the unlock animation controller, so
@@ -99,7 +107,7 @@
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
 
         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
-            remoteAnimationTarget,
+            remoteAnimationTargets,
             0 /* startTime */,
             false /* requestedShowSurfaceBehindKeyguard */
         )
@@ -130,7 +138,7 @@
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(false)
 
         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
-            remoteAnimationTarget,
+            remoteAnimationTargets,
             0 /* startTime */,
             false /* requestedShowSurfaceBehindKeyguard */
         )
@@ -154,7 +162,7 @@
         `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false)
 
         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
-            remoteAnimationTarget,
+            remoteAnimationTargets,
             0 /* startTime */,
             true /* requestedShowSurfaceBehindKeyguard */
         )
@@ -176,7 +184,7 @@
         `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true)
 
         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
-            remoteAnimationTarget,
+            remoteAnimationTargets,
             0 /* startTime */,
             true /* requestedShowSurfaceBehindKeyguard */
         )
@@ -196,7 +204,7 @@
     @Test
     fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() {
         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
-            remoteAnimationTarget,
+            remoteAnimationTargets,
             0 /* startTime */,
             false /* requestedShowSurfaceBehindKeyguard */
         )
@@ -210,7 +218,7 @@
         `when`(notificationShadeWindowController.isLaunchingActivity).thenReturn(true)
 
         keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
-            remoteAnimationTarget,
+            remoteAnimationTargets,
             0 /* startTime */,
             true /* requestedShowSurfaceBehindKeyguard */
         )
@@ -218,4 +226,53 @@
         assertFalse(keyguardUnlockAnimationController.canPerformInWindowLauncherAnimations())
         assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
     }
-}
\ No newline at end of file
+
+    @Test
+    fun playCannedUnlockAnimation_nullSmartspaceView_doesNotThrowExecption() {
+        keyguardUnlockAnimationController.lockscreenSmartspace = null
+        keyguardUnlockAnimationController.willUnlockWithInWindowLauncherAnimations = true
+
+        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+                remoteAnimationTargets,
+                0 /* startTime */,
+                false /* requestedShowSurfaceBehindKeyguard */
+        )
+
+        assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+    }
+
+    /**
+     * If we are not wake and unlocking, we expect the unlock animation to play normally.
+     */
+    @Test
+    fun surfaceAnimation_multipleTargets() {
+        keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+                arrayOf(remoteTarget1, remoteTarget2),
+                0 /* startTime */,
+                false /* requestedShowSurfaceBehindKeyguard */
+        )
+
+        // Set appear to 50%, we'll just verify that we're not applying the identity matrix which
+        // means an animation is in progress.
+        keyguardUnlockAnimationController.setSurfaceBehindAppearAmount(0.5f)
+
+        val captor = forClass(SyncRtSurfaceTransactionApplier.SurfaceParams::class.java)
+        verify(surfaceTransactionApplier, times(2)).scheduleApply(captor.capture())
+
+        val allParams = captor.allValues
+
+        val remainingTargets = mutableListOf(surfaceControl1, surfaceControl2)
+        allParams.forEach { params ->
+            assertTrue(!params.matrix.isIdentity)
+            remainingTargets.remove(params.surface)
+        }
+
+        // Make sure we called applyParams with each of the surface controls once. The order does
+        // not matter, so don't explicitly check for that.
+        assertTrue(remainingTargets.isEmpty())
+
+        // Since the animation is running, we should not have finished the remote animation.
+        verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished(
+                false /* cancelled */)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 3aa2266..ba1e168 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Position
+import com.android.systemui.doze.DozeHost
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.argumentCaptor
@@ -40,6 +41,7 @@
 class KeyguardRepositoryImplTest : SysuiTestCase() {
 
     @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var dozeHost: DozeHost
     @Mock private lateinit var keyguardStateController: KeyguardStateController
 
     private lateinit var underTest: KeyguardRepositoryImpl
@@ -48,7 +50,12 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        underTest = KeyguardRepositoryImpl(statusBarStateController, keyguardStateController)
+        underTest =
+            KeyguardRepositoryImpl(
+                statusBarStateController,
+                keyguardStateController,
+                dozeHost,
+            )
     }
 
     @Test
@@ -129,8 +136,8 @@
         var latest: Boolean? = null
         val job = underTest.isDozing.onEach { latest = it }.launchIn(this)
 
-        val captor = argumentCaptor<StatusBarStateController.StateListener>()
-        verify(statusBarStateController).addCallback(captor.capture())
+        val captor = argumentCaptor<DozeHost.Callback>()
+        verify(dozeHost).addCallback(captor.capture())
 
         captor.value.onDozingChanged(true)
         assertThat(latest).isTrue()
@@ -139,7 +146,7 @@
         assertThat(latest).isFalse()
 
         job.cancel()
-        verify(statusBarStateController).removeCallback(captor.value)
+        verify(dozeHost).removeCallback(captor.value)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 9acd21c..9a91ea91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -51,18 +51,19 @@
         @Parameters(
             name =
                 "feature enabled = {0}, has favorites = {1}, has service infos = {2}, can show" +
-                    " while locked = {3} - expected visible = {4}"
+                    " while locked = {3}, visibility is AVAILABLE {4} - expected visible = {5}"
         )
         @JvmStatic
         fun data() =
-            (0 until 16)
+            (0 until 32)
                 .map { combination ->
                     arrayOf(
-                        /* isFeatureEnabled= */ combination and 0b1000 != 0,
-                        /* hasFavorites= */ combination and 0b0100 != 0,
-                        /* hasServiceInfos= */ combination and 0b0010 != 0,
-                        /* canShowWhileLocked= */ combination and 0b0001 != 0,
-                        /* isVisible= */ combination == 0b1111,
+                        /* isFeatureEnabled= */ combination and 0b10000 != 0,
+                        /* hasFavorites= */ combination and 0b01000 != 0,
+                        /* hasServiceInfos= */ combination and 0b00100 != 0,
+                        /* canShowWhileLocked= */ combination and 0b00010 != 0,
+                        /* visibilityAvailable= */ combination and 0b00001 != 0,
+                        /* isVisible= */ combination == 0b11111,
                     )
                 }
                 .toList()
@@ -81,7 +82,8 @@
     @JvmField @Parameter(1) var hasFavorites: Boolean = false
     @JvmField @Parameter(2) var hasServiceInfos: Boolean = false
     @JvmField @Parameter(3) var canShowWhileLocked: Boolean = false
-    @JvmField @Parameter(4) var isVisible: Boolean = false
+    @JvmField @Parameter(4) var isVisibilityAvailable: Boolean = false
+    @JvmField @Parameter(5) var isVisibleExpected: Boolean = false
 
     @Before
     fun setUp() {
@@ -93,6 +95,14 @@
             .thenReturn(Optional.of(controlsListingController))
         whenever(component.canShowWhileLockedSetting)
             .thenReturn(MutableStateFlow(canShowWhileLocked))
+        whenever(component.getVisibility())
+            .thenReturn(
+                if (isVisibilityAvailable) {
+                    ControlsComponent.Visibility.AVAILABLE
+                } else {
+                    ControlsComponent.Visibility.UNAVAILABLE
+                }
+            )
 
         underTest =
             HomeControlsKeyguardQuickAffordanceConfig(
@@ -128,7 +138,7 @@
 
         assertThat(values.last())
             .isInstanceOf(
-                if (isVisible) {
+                if (isVisibleExpected) {
                     KeyguardQuickAffordanceConfig.State.Visible::class.java
                 } else {
                     KeyguardQuickAffordanceConfig.State.Hidden::class.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 059487d..dede4ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -69,6 +69,7 @@
         val controlsController = mock<ControlsController>()
         whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
         whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+        whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
         whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
 
         val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
@@ -87,6 +88,7 @@
         val controlsController = mock<ControlsController>()
         whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
         whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+        whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
         whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
 
         val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
index d3fc29f..19d8412 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
@@ -36,6 +36,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -110,6 +111,10 @@
                 .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
                 .onEach { latest = it }
                 .launchIn(this)
+        // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+        // produce an initial value. We yield to give the coroutine time to emit the first real
+        // value from our config.
+        yield()
 
         assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
         val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
@@ -136,6 +141,10 @@
                 .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
                 .onEach { latest = it }
                 .launchIn(this)
+        // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+        // produce an initial value. We yield to give the coroutine time to emit the first real
+        // value from our config.
+        yield()
 
         assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
         val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 14b85b8..c612091 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -224,7 +224,10 @@
         repository.setAnimateDozingTransitions(false)
         yield()
 
-        assertThat(values).isEqualTo(listOf(false, true, false))
+        // Note the extra false value in the beginning. This is to cover for the initial value
+        // inserted by the quick affordance interactor which it does to cover for config
+        // implementations that don't emit an initial value.
+        assertThat(values).isEqualTo(listOf(false, false, true, false))
         job.cancel()
     }
 
@@ -372,6 +375,10 @@
 
         var latest: KeyguardQuickAffordanceViewModel? = null
         val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+        // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+        // produce an initial value. We yield to give the coroutine time to emit the first real
+        // value from our config.
+        yield()
 
         assertQuickAffordanceViewModel(
             viewModel = latest,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index 1bc1972..5a50a9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import javax.inject.Provider
@@ -38,6 +39,8 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
@@ -71,6 +74,10 @@
     @Mock lateinit var player: TransitionLayout
     @Mock lateinit var recommendationViewHolder: RecommendationViewHolder
     @Mock lateinit var recommendations: TransitionLayout
+    @Mock lateinit var mediaPlayer: MediaControlPanel
+    @Mock lateinit var mediaViewController: MediaViewController
+    @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
+    @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
 
     private val clock = FakeSystemClock()
     private lateinit var mediaCarouselController: MediaCarouselController
@@ -94,7 +101,10 @@
             logger,
             debugLogger
         )
-
+        verify(mediaDataManager).addListener(capture(listener))
+        whenever(mediaControlPanelFactory.get()).thenReturn(mediaPlayer)
+        whenever(mediaPlayer.mediaViewController).thenReturn(mediaViewController)
+        whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
         MediaPlayerData.clear()
     }
 
@@ -305,4 +315,63 @@
         verifyNoMoreInteractions(mediaViewHolder)
         verify(recommendationViewHolder.recommendations).bottom = 75
     }
+
+    fun testMediaLoaded_ScrollToActivePlayer() {
+        listener.value.onMediaDataLoaded("playing local",
+                null,
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+        )
+        listener.value.onMediaDataLoaded("paused local",
+                null,
+                DATA.copy(active = true, isPlaying = false,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
+        // adding a media recommendation card.
+        MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+                false, clock)
+        mediaCarouselController.shouldScrollToActivePlayer = true
+        // switching between media players.
+        listener.value.onMediaDataLoaded("playing local",
+        "playing local",
+                DATA.copy(active = true, isPlaying = false,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true)
+        )
+        listener.value.onMediaDataLoaded("paused local",
+                "paused local",
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
+
+        assertEquals(
+                MediaPlayerData.getMediaPlayerIndex("paused local"),
+                mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+        )
+    }
+
+    @Test
+    fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
+        MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+                false, clock)
+        listener.value.onMediaDataLoaded("playing local",
+                null,
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+        )
+
+        var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
+        assertEquals(
+                playerIndex,
+                mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+        )
+        assertEquals( playerIndex, 0)
+
+        // Replaying the same media player one more time.
+        // And check that the card stays in its position.
+        listener.value.onMediaDataLoaded("playing local",
+                null,
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+        )
+        playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
+        assertEquals(playerIndex, 0)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 18bfd04..954b438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
 import com.android.systemui.dreams.DreamOverlayStateController
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.dream.MediaDreamComplication
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.testing.FakeNotifPanelEvents
 import com.android.systemui.statusbar.StatusBarState
@@ -38,6 +39,8 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.animation.UniqueObjectHostView
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.utils.os.FakeHandler
 import com.google.common.truth.Truth.assertThat
@@ -79,6 +82,9 @@
     private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
     @Captor
     private lateinit var statusBarCallback: ArgumentCaptor<(StatusBarStateController.StateListener)>
+    @Captor
+    private lateinit var dreamOverlayCallback:
+            ArgumentCaptor<(DreamOverlayStateController.Callback)>
     @JvmField
     @Rule
     val mockito = MockitoJUnit.rule()
@@ -113,6 +119,7 @@
                 fakeHandler,)
         verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
         verify(statusBarStateController).addCallback(statusBarCallback.capture())
+        verify(dreamOverlayStateController).addCallback(dreamOverlayCallback.capture())
         setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
         setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
         setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
@@ -332,6 +339,27 @@
         assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
     }
 
+    @Test
+    fun testDream() {
+        goToDream()
+        setMediaDreamComplicationEnabled(true)
+        verify(mediaCarouselController).onDesiredLocationChanged(
+                eq(MediaHierarchyManager.LOCATION_DREAM_OVERLAY),
+                nullable(),
+                eq(false),
+                anyLong(),
+                anyLong())
+        clearInvocations(mediaCarouselController)
+
+        setMediaDreamComplicationEnabled(false)
+        verify(mediaCarouselController).onDesiredLocationChanged(
+                eq(MediaHierarchyManager.LOCATION_QQS),
+                any(MediaHostState::class.java),
+                eq(false),
+                anyLong(),
+                anyLong())
+    }
+
     private fun enableSplitShade() {
         context.getOrCreateTestableResources().addOverride(
             R.bool.config_use_split_notification_shade, true
@@ -343,6 +371,8 @@
         whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
         statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+        whenever(dreamOverlayStateController.isOverlayActive).thenReturn(false)
+        dreamOverlayCallback.value.onStateChanged()
         clearInvocations(mediaCarouselController)
     }
 
@@ -354,6 +384,17 @@
         )
     }
 
+    private fun goToDream() {
+        whenever(dreamOverlayStateController.isOverlayActive).thenReturn(true)
+        dreamOverlayCallback.value.onStateChanged()
+    }
+
+    private fun setMediaDreamComplicationEnabled(enabled: Boolean) {
+        val complications = if (enabled) listOf(mock<MediaDreamComplication>()) else emptyList()
+        whenever(dreamOverlayStateController.complications).thenReturn(complications)
+        dreamOverlayCallback.value.onComplicationsChanged()
+    }
+
     private fun expandQS() {
         mediaHierarchyManager.qsExpansion = 1.0f
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
index 2e864dc..0bfc034 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
@@ -72,13 +72,13 @@
     }
 
     @Test
-    public void testComplicationAddition() {
+    public void testOnMediaDataLoaded_complicationAddition() {
         final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
                 mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
-
         sentinel.start();
 
         final MediaDataManager.Listener listener = captureMediaDataListener();
+
         when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
         listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */ true,
                 /* receivedSmartspaceCardLatency= */ 0, /* isSsReactived= */ false);
@@ -90,6 +90,19 @@
         verify(mDreamOverlayStateController).addComplication(eq(mMediaEntryComplication));
         verify(mDreamOverlayStateController, never()).addComplication(
                 not(eq(mMediaEntryComplication)));
+    }
+
+    @Test
+    public void testOnMediaDataRemoved_complicationRemoval() {
+        final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+                mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
+        sentinel.start();
+
+        final MediaDataManager.Listener listener = captureMediaDataListener();
+
+        when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
 
         listener.onMediaDataRemoved(mKey);
         verify(mDreamOverlayStateController, never()).removeComplication(any());
@@ -100,7 +113,30 @@
     }
 
     @Test
-    public void testMediaDreamSentinel_mediaComplicationDisabled_doNotAddComplication() {
+    public void testOnMediaDataLoaded_complicationRemoval() {
+        final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+                mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
+        sentinel.start();
+
+        final MediaDataManager.Listener listener = captureMediaDataListener();
+
+        when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+        verify(mDreamOverlayStateController, never()).removeComplication(any());
+
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+        verify(mDreamOverlayStateController, never()).removeComplication(any());
+
+        when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+        verify(mDreamOverlayStateController).removeComplication(eq(mMediaEntryComplication));
+    }
+
+    @Test
+    public void testOnMediaDataLoaded_mediaComplicationDisabled_doesNotAddComplication() {
         when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false);
 
         final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
deleted file mode 100644
index f133068..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.taptotransfer.common
-
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager
-import android.graphics.drawable.Drawable
-import android.os.PowerManager
-import android.view.View
-import android.view.ViewGroup
-import android.view.WindowManager
-import android.view.accessibility.AccessibilityManager
-import android.widget.ImageView
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
-import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.capture
-import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.mockito.ArgumentCaptor
-import org.mockito.Mock
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-class MediaTttChipControllerCommonTest : SysuiTestCase() {
-    private lateinit var controllerCommon: TestControllerCommon
-
-    private lateinit var fakeClock: FakeSystemClock
-    private lateinit var fakeExecutor: FakeExecutor
-
-    private lateinit var appIconFromPackageName: Drawable
-    @Mock
-    private lateinit var packageManager: PackageManager
-    @Mock
-    private lateinit var applicationInfo: ApplicationInfo
-    @Mock
-    private lateinit var logger: MediaTttLogger
-    @Mock
-    private lateinit var accessibilityManager: AccessibilityManager
-    @Mock
-    private lateinit var configurationController: ConfigurationController
-    @Mock
-    private lateinit var windowManager: WindowManager
-    @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
-    private lateinit var powerManager: PowerManager
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
-        appIconFromPackageName = context.getDrawable(R.drawable.ic_cake)!!
-        whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName)
-        whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME)
-        whenever(packageManager.getApplicationInfo(
-            any(), any<PackageManager.ApplicationInfoFlags>()
-        )).thenThrow(PackageManager.NameNotFoundException())
-        whenever(packageManager.getApplicationInfo(
-            eq(PACKAGE_NAME), any<PackageManager.ApplicationInfoFlags>()
-        )).thenReturn(applicationInfo)
-        context.setMockPackageManager(packageManager)
-
-        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any()))
-            .thenReturn(TIMEOUT_MS.toInt())
-
-        fakeClock = FakeSystemClock()
-        fakeExecutor = FakeExecutor(fakeClock)
-
-        controllerCommon = TestControllerCommon(
-                context,
-                logger,
-                windowManager,
-                viewUtil,
-                fakeExecutor,
-                accessibilityManager,
-                configurationController,
-                powerManager,
-        )
-    }
-
-    @Test
-    fun displayChip_chipAdded() {
-        controllerCommon.displayChip(getState())
-
-        verify(windowManager).addView(any(), any())
-    }
-
-    @Test
-    fun displayChip_screenOff_screenWakes() {
-        whenever(powerManager.isScreenOn).thenReturn(false)
-
-        controllerCommon.displayChip(getState())
-
-        verify(powerManager).wakeUp(any(), any(), any())
-    }
-
-    @Test
-    fun displayChip_screenAlreadyOn_screenNotWoken() {
-        whenever(powerManager.isScreenOn).thenReturn(true)
-
-        controllerCommon.displayChip(getState())
-
-        verify(powerManager, never()).wakeUp(any(), any(), any())
-    }
-
-    @Test
-    fun displayChip_twice_chipNotAddedTwice() {
-        controllerCommon.displayChip(getState())
-        reset(windowManager)
-
-        controllerCommon.displayChip(getState())
-        verify(windowManager, never()).addView(any(), any())
-    }
-
-    @Test
-    fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
-        val state = getState()
-        controllerCommon.displayChip(state)
-        reset(windowManager)
-
-        fakeClock.advanceTime(TIMEOUT_MS - 1)
-
-        verify(windowManager, never()).removeView(any())
-    }
-
-    @Test
-    fun displayChip_chipDisappearsAfterTimeout() {
-        val state = getState()
-        controllerCommon.displayChip(state)
-        reset(windowManager)
-
-        fakeClock.advanceTime(TIMEOUT_MS + 1)
-
-        verify(windowManager).removeView(any())
-    }
-
-    @Test
-    fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
-        // First, display the chip
-        val state = getState()
-        controllerCommon.displayChip(state)
-
-        // After some time, re-display the chip
-        val waitTime = 1000L
-        fakeClock.advanceTime(waitTime)
-        controllerCommon.displayChip(getState())
-
-        // Wait until the timeout for the first display would've happened
-        fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1)
-
-        // Verify we didn't hide the chip
-        verify(windowManager, never()).removeView(any())
-    }
-
-    @Test
-    fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
-        // First, display the chip
-        val state = getState()
-        controllerCommon.displayChip(state)
-
-        // After some time, re-display the chip
-        fakeClock.advanceTime(1000L)
-        controllerCommon.displayChip(getState())
-
-        // Ensure we still hide the chip eventually
-        fakeClock.advanceTime(TIMEOUT_MS + 1)
-
-        verify(windowManager).removeView(any())
-    }
-
-    @Test
-    fun displayScaleChange_chipReinflatedWithMostRecentState() {
-        controllerCommon.displayChip(getState(name = "First name"))
-        controllerCommon.displayChip(getState(name = "Second name"))
-        reset(windowManager)
-
-        getConfigurationListener().onDensityOrFontScaleChanged()
-
-        verify(windowManager).removeView(any())
-        verify(windowManager).addView(any(), any())
-        assertThat(controllerCommon.mostRecentChipInfo?.name).isEqualTo("Second name")
-    }
-
-    @Test
-    fun removeChip_chipRemovedAndRemovalLogged() {
-        // First, add the chip
-        controllerCommon.displayChip(getState())
-
-        // Then, remove it
-        val reason = "test reason"
-        controllerCommon.removeChip(reason)
-
-        verify(windowManager).removeView(any())
-        verify(logger).logChipRemoval(reason)
-    }
-
-    @Test
-    fun removeChip_noAdd_viewNotRemoved() {
-        controllerCommon.removeChip("reason")
-
-        verify(windowManager, never()).removeView(any())
-    }
-
-    @Test
-    fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
-
-        assertThat(chipView.getAppIconView().drawable).isNotNull()
-    }
-
-    @Test
-    fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(
-            chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
-        )
-
-        assertThat(chipView.getAppIconView().drawable).isNotNull()
-    }
-
-    @Test
-    fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
-
-        assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
-    }
-
-    @Test
-    fun setIcon_hasAppIconDrawable_iconIsDrawable() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        val drawable = context.getDrawable(R.drawable.ic_alarm)!!
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null)
-
-        assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
-    }
-
-    @Test
-    fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
-
-        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
-    }
-
-    @Test
-    fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(
-            chipView, appPackageName = "fakePackageName", appNameOverride = null
-        )
-
-        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
-    }
-
-    @Test
-    fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null)
-
-        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
-    }
-
-    @Test
-    fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        val appName = "Override App Name"
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName)
-
-        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
-    }
-
-    @Test
-    fun setIcon_iconSizeMatchesGetIconSize() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
-
-        controllerCommon.setIcon(chipView, PACKAGE_NAME)
-        chipView.measure(
-            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
-            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
-        )
-
-        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
-        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
-    }
-
-    private fun getState(name: String = "name") = ChipInfo(name)
-
-    private fun getChipView(): ViewGroup {
-        val viewCaptor = ArgumentCaptor.forClass(View::class.java)
-        verify(windowManager).addView(viewCaptor.capture(), any())
-        return viewCaptor.value as ViewGroup
-    }
-
-    private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
-
-    private fun getConfigurationListener(): ConfigurationListener {
-        val callbackCaptor = argumentCaptor<ConfigurationListener>()
-        verify(configurationController).addCallback(capture(callbackCaptor))
-        return callbackCaptor.value
-    }
-
-    inner class TestControllerCommon(
-        context: Context,
-        logger: MediaTttLogger,
-        windowManager: WindowManager,
-        viewUtil: ViewUtil,
-        @Main mainExecutor: DelayableExecutor,
-        accessibilityManager: AccessibilityManager,
-        configurationController: ConfigurationController,
-        powerManager: PowerManager,
-    ) : MediaTttChipControllerCommon<ChipInfo>(
-        context,
-        logger,
-        windowManager,
-        viewUtil,
-        mainExecutor,
-        accessibilityManager,
-        configurationController,
-        powerManager,
-        R.layout.media_ttt_chip,
-    ) {
-        var mostRecentChipInfo: ChipInfo? = null
-
-        override val windowLayoutParams = commonWindowLayoutParams
-        override fun updateChipView(newChipInfo: ChipInfo, currentChipView: ViewGroup) {
-            super.updateChipView(newChipInfo, currentChipView)
-            mostRecentChipInfo = newChipInfo
-        }
-        override fun getIconSize(isAppIcon: Boolean): Int = ICON_SIZE
-    }
-
-    inner class ChipInfo(val name: String) : ChipInfoCommon {
-        override fun getTimeoutMs() = 1L
-    }
-}
-
-private const val PACKAGE_NAME = "com.android.systemui"
-private const val APP_NAME = "Fake App Name"
-private const val TIMEOUT_MS = 10000L
-private const val ICON_SIZE = 47
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
index d95e5c4..1078cda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
@@ -23,11 +23,11 @@
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.log.LogcatEchoTracker
 import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mockito.mock
-import java.io.PrintWriter
-import java.io.StringWriter
 
 @SmallTest
 class MediaTttLoggerTest : SysuiTestCase() {
@@ -43,32 +43,46 @@
     }
 
     @Test
-    fun logStateChange_bufferHasDeviceTypeTagAndStateNameAndId() {
+    fun logStateChange_bufferHasDeviceTypeTagAndParamInfo() {
         val stateName = "test state name"
         val id = "test id"
+        val packageName = "this.is.a.package"
 
-        logger.logStateChange(stateName, id)
+        logger.logStateChange(stateName, id, packageName)
 
-        val stringWriter = StringWriter()
-        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
-        val actualString = stringWriter.toString()
-
+        val actualString = getStringFromBuffer()
         assertThat(actualString).contains(DEVICE_TYPE_TAG)
         assertThat(actualString).contains(stateName)
         assertThat(actualString).contains(id)
+        assertThat(actualString).contains(packageName)
     }
 
     @Test
-    fun logChipRemoval_bufferHasDeviceTypeAndReason() {
-        val reason = "test reason"
-        logger.logChipRemoval(reason)
+    fun logPackageNotFound_bufferHasPackageName() {
+        val packageName = "this.is.a.package"
 
+        logger.logPackageNotFound(packageName)
+
+        val actualString = getStringFromBuffer()
+        assertThat(actualString).contains(packageName)
+    }
+
+    @Test
+    fun logRemovalBypass_bufferHasReasons() {
+        val removalReason = "fakeRemovalReason"
+        val bypassReason = "fakeBypassReason"
+
+        logger.logRemovalBypass(removalReason, bypassReason)
+
+        val actualString = getStringFromBuffer()
+        assertThat(actualString).contains(removalReason)
+        assertThat(actualString).contains(bypassReason)
+    }
+
+    private fun getStringFromBuffer(): String {
         val stringWriter = StringWriter()
         buffer.dump(PrintWriter(stringWriter), tailLength = 0)
-        val actualString = stringWriter.toString()
-
-        assertThat(actualString).contains(DEVICE_TYPE_TAG)
-        assertThat(actualString).contains(reason)
+        return stringWriter.toString()
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
new file mode 100644
index 0000000..37f6434
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.common
+
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.graphics.drawable.Drawable
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.internal.widget.CachingIconView
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MediaTttUtilsTest : SysuiTestCase() {
+
+    private lateinit var appIconFromPackageName: Drawable
+    @Mock private lateinit var packageManager: PackageManager
+    @Mock private lateinit var applicationInfo: ApplicationInfo
+    @Mock private lateinit var logger: MediaTttLogger
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        // Set up our package manager to give valid information for [PACKAGE_NAME] only
+        appIconFromPackageName = context.getDrawable(R.drawable.ic_cake)!!
+        whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName)
+        whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME)
+        whenever(
+                packageManager.getApplicationInfo(any(), any<PackageManager.ApplicationInfoFlags>())
+            )
+            .thenThrow(PackageManager.NameNotFoundException())
+        whenever(
+                packageManager.getApplicationInfo(
+                    Mockito.eq(PACKAGE_NAME),
+                    any<PackageManager.ApplicationInfoFlags>()
+                )
+            )
+            .thenReturn(applicationInfo)
+        context.setMockPackageManager(packageManager)
+    }
+
+    @Test
+    fun getIconInfoFromPackageName_nullPackageName_returnsDefault() {
+        val iconInfo =
+            MediaTttUtils.getIconInfoFromPackageName(context, appPackageName = null, logger)
+
+        assertThat(iconInfo.isAppIcon).isFalse()
+        assertThat(iconInfo.contentDescription)
+            .isEqualTo(context.getString(R.string.media_output_dialog_unknown_launch_app_name))
+    }
+
+    @Test
+    fun getIconInfoFromPackageName_invalidPackageName_returnsDefault() {
+        val iconInfo = MediaTttUtils.getIconInfoFromPackageName(context, "fakePackageName", logger)
+
+        assertThat(iconInfo.isAppIcon).isFalse()
+        assertThat(iconInfo.contentDescription)
+            .isEqualTo(context.getString(R.string.media_output_dialog_unknown_launch_app_name))
+    }
+
+    @Test
+    fun getIconInfoFromPackageName_validPackageName_returnsAppInfo() {
+        val iconInfo = MediaTttUtils.getIconInfoFromPackageName(context, PACKAGE_NAME, logger)
+
+        assertThat(iconInfo.isAppIcon).isTrue()
+        assertThat(iconInfo.drawable).isEqualTo(appIconFromPackageName)
+        assertThat(iconInfo.contentDescription).isEqualTo(APP_NAME)
+    }
+
+    @Test
+    fun setIcon_viewHasIconAndContentDescription() {
+        val view = CachingIconView(context)
+        val icon = context.getDrawable(R.drawable.ic_celebration)!!
+        val contentDescription = "Happy birthday!"
+
+        MediaTttUtils.setIcon(view, icon, contentDescription)
+
+        assertThat(view.drawable).isEqualTo(icon)
+        assertThat(view.contentDescription).isEqualTo(contentDescription)
+    }
+
+    @Test
+    fun setIcon_iconSizeNull_viewSizeDoesNotChange() {
+        val view = CachingIconView(context)
+        val size = 456
+        view.layoutParams = FrameLayout.LayoutParams(size, size)
+
+        MediaTttUtils.setIcon(view, context.getDrawable(R.drawable.ic_cake)!!, "desc")
+
+        assertThat(view.layoutParams.width).isEqualTo(size)
+        assertThat(view.layoutParams.height).isEqualTo(size)
+    }
+
+    @Test
+    fun setIcon_iconSizeProvided_viewSizeUpdates() {
+        val view = CachingIconView(context)
+        val size = 456
+        view.layoutParams = FrameLayout.LayoutParams(size, size)
+
+        val newSize = 40
+        MediaTttUtils.setIcon(
+            view,
+            context.getDrawable(R.drawable.ic_cake)!!,
+            "desc",
+            iconSize = newSize
+        )
+
+        assertThat(view.layoutParams.width).isEqualTo(newSize)
+        assertThat(view.layoutParams.height).isEqualTo(newSize)
+    }
+}
+
+private const val PACKAGE_NAME = "com.android.systemui"
+private const val APP_NAME = "Fake App Name"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 171d893..d41ad48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -41,7 +41,6 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -74,8 +73,6 @@
     @Mock
     private lateinit var windowManager: WindowManager
     @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
     private lateinit var commandQueue: CommandQueue
     private lateinit var commandQueueCallback: CommandQueue.Callbacks
     private lateinit var fakeAppIconDrawable: Drawable
@@ -102,7 +99,6 @@
             context,
             logger,
             windowManager,
-            viewUtil,
             FakeExecutor(FakeSystemClock()),
             accessibilityManager,
             configurationController,
@@ -177,37 +173,72 @@
             null
         )
 
-        verify(logger).logStateChange(any(), any())
+        verify(logger).logStateChange(any(), any(), any())
     }
 
     @Test
-    fun setIcon_isAppIcon_usesAppIconSize() {
-        controllerReceiver.displayChip(getChipReceiverInfo())
+    fun updateView_noOverrides_usesInfoFromAppIcon() {
+        controllerReceiver.displayView(
+            ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appNameOverride = null)
+        )
+
+        val view = getChipView()
+        assertThat(view.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
+        assertThat(view.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+    }
+
+    @Test
+    fun updateView_appIconOverride_usesOverride() {
+        val drawableOverride = context.getDrawable(R.drawable.ic_celebration)!!
+
+        controllerReceiver.displayView(
+            ChipReceiverInfo(routeInfo, drawableOverride, appNameOverride = null)
+        )
+
+        val view = getChipView()
+        assertThat(view.getAppIconView().drawable).isEqualTo(drawableOverride)
+    }
+
+    @Test
+    fun updateView_appNameOverride_usesOverride() {
+        val appNameOverride = "Sweet New App"
+
+        controllerReceiver.displayView(
+            ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appNameOverride)
+        )
+
+        val view = getChipView()
+        assertThat(view.getAppIconView().contentDescription).isEqualTo(appNameOverride)
+    }
+
+    @Test
+    fun updateView_isAppIcon_usesAppIconSize() {
+        controllerReceiver.displayView(getChipReceiverInfo(packageName = PACKAGE_NAME))
         val chipView = getChipView()
 
-        controllerReceiver.setIcon(chipView, PACKAGE_NAME)
         chipView.measure(
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
         )
 
-        val expectedSize = controllerReceiver.getIconSize(isAppIcon = true)
+        val expectedSize =
+            context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver)
         assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
         assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
     }
 
     @Test
-    fun setIcon_notAppIcon_usesGenericIconSize() {
-        controllerReceiver.displayChip(getChipReceiverInfo())
+    fun updateView_notAppIcon_usesGenericIconSize() {
+        controllerReceiver.displayView(getChipReceiverInfo(packageName = null))
         val chipView = getChipView()
 
-        controllerReceiver.setIcon(chipView, appPackageName = null)
         chipView.measure(
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
         )
 
-        val expectedSize = controllerReceiver.getIconSize(isAppIcon = false)
+        val expectedSize =
+            context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_size_receiver)
         assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
         assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
     }
@@ -230,8 +261,13 @@
         return viewCaptor.value as ViewGroup
     }
 
-    private fun getChipReceiverInfo(): ChipReceiverInfo =
-        ChipReceiverInfo(routeInfo, null, null)
+    private fun getChipReceiverInfo(packageName: String?): ChipReceiverInfo {
+        val routeInfo = MediaRoute2Info.Builder("id", "Test route name")
+            .addFeature("feature")
+            .setClientPackageName(packageName)
+            .build()
+        return ChipReceiverInfo(routeInfo, null, null)
+    }
 
     private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 1061e3c..ff0faf9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -42,7 +42,6 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -51,8 +50,8 @@
 import org.mockito.Mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -75,8 +74,6 @@
     @Mock
     private lateinit var windowManager: WindowManager
     @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
     private lateinit var commandQueue: CommandQueue
     private lateinit var commandQueueCallback: CommandQueue.Callbacks
     private lateinit var fakeAppIconDrawable: Drawable
@@ -110,7 +107,6 @@
             context,
             logger,
             windowManager,
-            viewUtil,
             fakeExecutor,
             accessibilityManager,
             configurationController,
@@ -303,13 +299,13 @@
             null
         )
 
-        verify(logger).logStateChange(any(), any())
+        verify(logger).logStateChange(any(), any(), any())
     }
 
     @Test
     fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
         val state = almostCloseToStartCast()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -325,7 +321,7 @@
     @Test
     fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
         val state = almostCloseToEndCast()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -341,7 +337,7 @@
     @Test
     fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
         val state = transferToReceiverTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -357,7 +353,7 @@
     @Test
     fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
         val state = transferToThisDeviceTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -373,7 +369,7 @@
     @Test
     fun transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
         val state = transferToReceiverSucceeded()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -387,7 +383,7 @@
 
     @Test
     fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() {
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback = null))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback = null))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -398,7 +394,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -414,7 +410,7 @@
             }
         }
 
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
         getChipView().getUndoButton().performClick()
 
         assertThat(undoCallbackCalled).isTrue()
@@ -425,7 +421,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
 
         getChipView().getUndoButton().performClick()
 
@@ -440,7 +436,7 @@
     @Test
     fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
         val state = transferToThisDeviceSucceeded()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -454,7 +450,7 @@
 
     @Test
     fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() {
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback = null))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback = null))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -465,7 +461,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -481,7 +477,7 @@
             }
         }
 
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
         getChipView().getUndoButton().performClick()
 
         assertThat(undoCallbackCalled).isTrue()
@@ -492,7 +488,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
 
         getChipView().getUndoButton().performClick()
 
@@ -507,7 +503,7 @@
     @Test
     fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
         val state = transferToReceiverFailed()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -523,7 +519,7 @@
     @Test
     fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
         val state = transferToThisDeviceFailed()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -538,24 +534,24 @@
 
     @Test
     fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
-        controllerSender.displayChip(almostCloseToStartCast())
-        controllerSender.displayChip(transferToReceiverTriggered())
+        controllerSender.displayView(almostCloseToStartCast())
+        controllerSender.displayView(transferToReceiverTriggered())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
     }
 
     @Test
     fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() {
-        controllerSender.displayChip(transferToReceiverTriggered())
-        controllerSender.displayChip(transferToReceiverSucceeded())
+        controllerSender.displayView(transferToReceiverTriggered())
+        controllerSender.displayView(transferToReceiverSucceeded())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
     }
 
     @Test
     fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() {
-        controllerSender.displayChip(transferToReceiverTriggered())
-        controllerSender.displayChip(
+        controllerSender.displayView(transferToReceiverTriggered())
+        controllerSender.displayView(
             transferToReceiverSucceeded(
                 object : IUndoMediaTransferCallback.Stub() {
                     override fun onUndoTriggered() {}
@@ -568,66 +564,166 @@
 
     @Test
     fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
-        controllerSender.displayChip(transferToReceiverSucceeded())
-        controllerSender.displayChip(almostCloseToStartCast())
+        controllerSender.displayView(transferToReceiverSucceeded())
+        controllerSender.displayView(almostCloseToStartCast())
 
         assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
     }
 
     @Test
     fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
-        controllerSender.displayChip(transferToReceiverTriggered())
-        controllerSender.displayChip(transferToReceiverFailed())
+        controllerSender.displayView(transferToReceiverTriggered())
+        controllerSender.displayView(transferToReceiverFailed())
 
         assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
-    fun transferToReceiverTriggeredThenRemoveChip_chipStillDisplayed() {
-        controllerSender.displayChip(transferToReceiverTriggered())
+    fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() {
+        controllerSender.displayView(transferToReceiverTriggered())
         fakeClock.advanceTime(1000L)
 
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
         fakeExecutor.runAllReady()
 
         verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
     }
 
     @Test
-    fun transferToReceiverTriggeredThenFarFromReceiver_eventuallyTimesOut() {
-        val state = transferToReceiverTriggered()
-        controllerSender.displayChip(state)
-        fakeClock.advanceTime(1000L)
-        controllerSender.removeChip("fakeRemovalReason")
+    fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() {
+        controllerSender.displayView(transferToReceiverTriggered())
 
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+            routeInfo,
+            null
+        )
+        fakeExecutor.runAllReady()
+
+        verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
+    }
+
+    @Test
+    fun transferToReceiverTriggeredThenRemoveView_eventuallyTimesOut() {
+        controllerSender.displayView(transferToReceiverTriggered())
+
+        controllerSender.removeView("fakeRemovalReason")
         fakeClock.advanceTime(TIMEOUT + 1L)
 
         verify(windowManager).removeView(any())
     }
 
     @Test
-    fun transferToThisDeviceTriggeredThenRemoveChip_chipStillDisplayed() {
-        controllerSender.displayChip(transferToThisDeviceTriggered())
+    fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() {
+        controllerSender.displayView(transferToThisDeviceTriggered())
         fakeClock.advanceTime(1000L)
 
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
         fakeExecutor.runAllReady()
 
         verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
     }
 
     @Test
-    fun transferToThisDeviceTriggeredThenFarFromReceiver_eventuallyTimesOut() {
-        val state = transferToThisDeviceTriggered()
-        controllerSender.displayChip(state)
-        fakeClock.advanceTime(1000L)
-        controllerSender.removeChip("fakeRemovalReason")
+    fun transferToThisDeviceTriggeredThenRemoveView_eventuallyTimesOut() {
+        controllerSender.displayView(transferToThisDeviceTriggered())
 
+        controllerSender.removeView("fakeRemovalReason")
         fakeClock.advanceTime(TIMEOUT + 1L)
 
         verify(windowManager).removeView(any())
     }
 
+    @Test
+    fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() {
+        controllerSender.displayView(transferToThisDeviceTriggered())
+
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+            routeInfo,
+            null
+        )
+        fakeExecutor.runAllReady()
+
+        verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
+    }
+
+    @Test
+    fun transferToReceiverSucceededThenRemoveView_viewStillDisplayed() {
+        controllerSender.displayView(transferToReceiverSucceeded())
+
+        controllerSender.removeView("fakeRemovalReason")
+        fakeExecutor.runAllReady()
+
+        verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
+    }
+
+    @Test
+    fun transferToReceiverSucceededThenRemoveView_eventuallyTimesOut() {
+        controllerSender.displayView(transferToReceiverSucceeded())
+
+        controllerSender.removeView("fakeRemovalReason")
+        fakeClock.advanceTime(TIMEOUT + 1L)
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() {
+        controllerSender.displayView(transferToReceiverSucceeded())
+
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+            routeInfo,
+            null
+        )
+        fakeExecutor.runAllReady()
+
+        verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
+    }
+
+    @Test
+    fun transferToThisDeviceSucceededThenRemoveView_viewStillDisplayed() {
+        controllerSender.displayView(transferToThisDeviceSucceeded())
+
+        controllerSender.removeView("fakeRemovalReason")
+        fakeExecutor.runAllReady()
+
+        verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
+    }
+
+    @Test
+    fun transferToThisDeviceSucceededThenRemoveView_eventuallyTimesOut() {
+        controllerSender.displayView(transferToThisDeviceSucceeded())
+
+        controllerSender.removeView("fakeRemovalReason")
+        fakeClock.advanceTime(TIMEOUT + 1L)
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() {
+        controllerSender.displayView(transferToThisDeviceSucceeded())
+
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+            routeInfo,
+            null
+        )
+        fakeExecutor.runAllReady()
+
+        verify(windowManager, never()).removeView(any())
+        verify(logger).logRemovalBypass(any(), any())
+    }
+
     private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
 
     private fun ViewGroup.getChipText(): String =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
new file mode 100644
index 0000000..249a91b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.power.data.repository
+
+import android.content.BroadcastReceiver
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.PowerManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class PowerRepositoryImplTest : SysuiTestCase() {
+
+    @Mock private lateinit var manager: PowerManager
+    @Mock private lateinit var dispatcher: BroadcastDispatcher
+    @Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
+    @Captor private lateinit var filterCaptor: ArgumentCaptor<IntentFilter>
+
+    private lateinit var underTest: PowerRepositoryImpl
+
+    private var isInteractive = true
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        isInteractive = true
+        whenever(manager.isInteractive).then { isInteractive }
+
+        underTest = PowerRepositoryImpl(manager = manager, dispatcher = dispatcher)
+    }
+
+    @Test
+    fun `isInteractive - registers for broadcasts`() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isInteractive.onEach {}.launchIn(this)
+
+            verifyRegistered()
+            assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_ON)).isTrue()
+            assertThat(filterCaptor.value.hasAction(Intent.ACTION_SCREEN_OFF)).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun `isInteractive - unregisters from broadcasts`() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.isInteractive.onEach {}.launchIn(this)
+            verifyRegistered()
+
+            job.cancel()
+
+            verify(dispatcher).unregisterReceiver(receiverCaptor.value)
+        }
+
+    @Test
+    fun `isInteractive - emits initial true value if screen was on`() =
+        runBlocking(IMMEDIATE) {
+            isInteractive = true
+            var value: Boolean? = null
+            val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+            verifyRegistered()
+
+            assertThat(value).isTrue()
+            job.cancel()
+        }
+
+    @Test
+    fun `isInteractive - emits initial false value if screen was off`() =
+        runBlocking(IMMEDIATE) {
+            isInteractive = false
+            var value: Boolean? = null
+            val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+            verifyRegistered()
+
+            assertThat(value).isFalse()
+            job.cancel()
+        }
+
+    @Test
+    fun `isInteractive - emits true when the screen turns on`() =
+        runBlocking(IMMEDIATE) {
+            var value: Boolean? = null
+            val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+            verifyRegistered()
+
+            isInteractive = true
+            receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON))
+
+            assertThat(value).isTrue()
+            job.cancel()
+        }
+
+    @Test
+    fun `isInteractive - emits false when the screen turns off`() =
+        runBlocking(IMMEDIATE) {
+            var value: Boolean? = null
+            val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+            verifyRegistered()
+
+            isInteractive = false
+            receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF))
+
+            assertThat(value).isFalse()
+            job.cancel()
+        }
+
+    @Test
+    fun `isInteractive - emits correctly over time`() =
+        runBlocking(IMMEDIATE) {
+            val values = mutableListOf<Boolean>()
+            val job = underTest.isInteractive.onEach(values::add).launchIn(this)
+            verifyRegistered()
+
+            isInteractive = false
+            receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF))
+            isInteractive = true
+            receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_ON))
+            isInteractive = false
+            receiverCaptor.value.onReceive(context, Intent(Intent.ACTION_SCREEN_OFF))
+
+            assertThat(values).isEqualTo(listOf(true, false, true, false))
+            job.cancel()
+        }
+
+    private fun verifyRegistered() {
+        // We must verify with all arguments, even those that are optional because they have default
+        // values because Mockito is forcing us to. Once we can use mockito-kotlin, we should be
+        // able to remove this.
+        verify(dispatcher)
+            .registerReceiver(
+                capture(receiverCaptor),
+                capture(filterCaptor),
+                isNull(),
+                isNull(),
+                anyInt(),
+                isNull(),
+            )
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
new file mode 100644
index 0000000..bf6a37e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.power.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class PowerInteractorTest : SysuiTestCase() {
+
+    private lateinit var underTest: PowerInteractor
+    private lateinit var repository: FakePowerRepository
+
+    @Before
+    fun setUp() {
+        repository =
+            FakePowerRepository(
+                initialInteractive = true,
+            )
+        underTest = PowerInteractor(repository = repository)
+    }
+
+    @Test
+    fun `isInteractive - screen turns off`() =
+        runBlocking(IMMEDIATE) {
+            repository.setInteractive(true)
+            var value: Boolean? = null
+            val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+            repository.setInteractive(false)
+
+            assertThat(value).isFalse()
+            job.cancel()
+        }
+
+    @Test
+    fun `isInteractive - becomes interactive`() =
+        runBlocking(IMMEDIATE) {
+            repository.setInteractive(false)
+            var value: Boolean? = null
+            val job = underTest.isInteractive.onEach { value = it }.launchIn(this)
+
+            repository.setInteractive(true)
+
+            assertThat(value).isTrue()
+            job.cancel()
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index f08ad24..5d5918d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -94,6 +94,7 @@
     @Mock private QSPanel.QSTileLayout mQQsTileLayout;
     @Mock private QSAnimator mQSAnimator;
     @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private QSSquishinessController mSquishinessController;
     private View mQsFragmentView;
 
     public QSFragmentTest() {
@@ -139,13 +140,15 @@
     }
 
     @Test
-    public void transitionToFullShade_inSplitShade_setsAlphaBasedOnProgress() {
+    public void transitionToFullShade_setsAlphaUsingShadeInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        enableSplitShade();
-        int transitionPxAmount = 123;
+        setStatusBarState(StatusBarState.SHADE);
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
 
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
 
         assertThat(mQsFragmentView.getAlpha())
                 .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
@@ -153,31 +156,32 @@
 
     @Test
     public void
-            transitionToFullShade_inSplitShade_onKeyguard_bouncerNotActive_usesShadeInterpolator() {
+            transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        enableSplitShade();
         setStatusBarState(StatusBarState.KEYGUARD);
         when(mQSPanelController.isBouncerInTransit()).thenReturn(false);
-        int transitionPxAmount = 123;
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
 
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
 
-        assertThat(mQsFragmentView.getAlpha())
-                .isEqualTo(ShadeInterpolation.getContentAlpha(transitionProgress));
+        assertThat(mQsFragmentView.getAlpha()).isEqualTo(transitionProgress);
     }
 
     @Test
     public void
-            transitionToFullShade_inSplitShade_onKeyguard_bouncerActive_usesBouncerInterpolator() {
+            transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        enableSplitShade();
         setStatusBarState(StatusBarState.KEYGUARD);
         when(mQSPanelController.isBouncerInTransit()).thenReturn(true);
-        int transitionPxAmount = 123;
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
+        float squishinessFraction = 0.5f;
 
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
 
         assertThat(mQsFragmentView.getAlpha())
                 .isEqualTo(
@@ -186,28 +190,44 @@
     }
 
     @Test
-    public void transitionToFullShade_notInSplitShade_alwaysSetsAlphaTo1() {
+    public void transitionToFullShade_inFullWidth_alwaysSetsAlphaTo1() {
         QSFragment fragment = resumeAndGetFragment();
-        disableSplitShade();
+        fragment.setIsNotificationPanelFullWidth(true);
 
-        int transitionPxAmount = 12;
+        boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.1f;
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        float squishinessFraction = 0.5f;
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
 
-        transitionPxAmount = 123;
         transitionProgress = 0.5f;
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
 
-        transitionPxAmount = 234;
         transitionProgress = 0.7f;
-        fragment.setTransitionToFullShadeAmount(transitionPxAmount, transitionProgress);
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
         assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
     }
 
     @Test
+    public void transitionToFullShade_setsSquishinessOnController() {
+        QSFragment fragment = resumeAndGetFragment();
+        boolean isTransitioningToFullShade = true;
+        float transitionProgress = 0.123f;
+        float squishinessFraction = 0.456f;
+
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
+
+        verify(mQsFragmentComponent.getQSSquishinessController())
+                .setSquishiness(squishinessFraction);
+    }
+
+    @Test
     public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() {
         // Random test values without any meaning. They just have to be different from each other.
         float expansion = 0.123f;
@@ -453,6 +473,7 @@
         when(mQsFragmentComponent.getQSFooterActionController())
                 .thenReturn(mQSFooterActionController);
         when(mQsFragmentComponent.getQSAnimator()).thenReturn(mQSAnimator);
+        when(mQsFragmentComponent.getQSSquishinessController()).thenReturn(mSquishinessController);
     }
 
     private QSFragment getFragment() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index b98be75..2db58be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -158,6 +158,13 @@
         assertThat(qsPanel.paddingBottom).isEqualTo(padding)
     }
 
+    @Test
+    fun testSetSquishinessFraction_noCrash() {
+        qsPanel.addView(qsPanel.mTileLayout as View, 0)
+        qsPanel.addView(FrameLayout(context))
+        qsPanel.setSquishinessFraction(0.5f)
+    }
+
     private infix fun View.isLeftOf(other: View): Boolean {
         val rect = Rect()
         getBoundsOnScreen(rect)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index e4751d1..2a4996f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -70,9 +70,13 @@
         val underTest = utils.footerActionsViewModel(showPowerButton = false)
         val settings = underTest.settings
 
-        assertThat(settings.contentDescription)
-            .isEqualTo(ContentDescription.Resource(R.string.accessibility_quick_settings_settings))
-        assertThat(settings.icon).isEqualTo(Icon.Resource(R.drawable.ic_settings))
+        assertThat(settings.icon)
+            .isEqualTo(
+                Icon.Resource(
+                    R.drawable.ic_settings,
+                    ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+                )
+            )
         assertThat(settings.background).isEqualTo(R.drawable.qs_footer_action_circle)
         assertThat(settings.iconTint).isNull()
     }
@@ -87,11 +91,13 @@
         val underTestWithPower = utils.footerActionsViewModel(showPowerButton = true)
         val power = underTestWithPower.power
         assertThat(power).isNotNull()
-        assertThat(power!!.contentDescription)
+        assertThat(power!!.icon)
             .isEqualTo(
-                ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+                Icon.Resource(
+                    android.R.drawable.ic_lock_power_off,
+                    ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+                )
             )
-        assertThat(power.icon).isEqualTo(Icon.Resource(android.R.drawable.ic_lock_power_off))
         assertThat(power.background).isEqualTo(R.drawable.qs_footer_action_circle_color)
         assertThat(power.iconTint)
             .isEqualTo(
@@ -164,14 +170,13 @@
         utils.setUserSwitcherEnabled(settings, true, userId)
         val userSwitcher = currentUserSwitcher()
         assertThat(userSwitcher).isNotNull()
-        assertThat(userSwitcher!!.contentDescription)
-            .isEqualTo(ContentDescription.Loaded("Signed in as foo"))
-        assertThat(userSwitcher.icon).isEqualTo(Icon.Loaded(picture))
+        assertThat(userSwitcher!!.icon)
+            .isEqualTo(Icon.Loaded(picture, ContentDescription.Loaded("Signed in as foo")))
         assertThat(userSwitcher.background).isEqualTo(R.drawable.qs_footer_action_circle)
 
         // Change the current user name.
         userSwitcherControllerWrapper.currentUserName = "bar"
-        assertThat(currentUserSwitcher()?.contentDescription)
+        assertThat(currentUserSwitcher()?.icon?.contentDescription)
             .isEqualTo(ContentDescription.Loaded("Signed in as bar"))
 
         fun iconTint(): Int? = currentUserSwitcher()!!.iconTint
@@ -243,7 +248,7 @@
         // Map any SecurityModel into a non-null SecurityButtonConfig.
         val buttonConfig =
             SecurityButtonConfig(
-                icon = Icon.Resource(0),
+                icon = Icon.Resource(res = 0, contentDescription = null),
                 text = "foo",
                 isClickable = true,
             )
@@ -340,7 +345,7 @@
         assertThat(foregroundServices.displayText).isTrue()
         securityToConfig = {
             SecurityButtonConfig(
-                icon = Icon.Resource(0),
+                icon = Icon.Resource(res = 0, contentDescription = null),
                 text = "foo",
                 isClickable = true,
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index ed98881..f7b9438e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -33,17 +33,18 @@
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.controller.ControlInfo
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.controller.StructureInfo
 import com.android.systemui.controls.dagger.ControlsComponent
 import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.controls.ui.ControlsActivity
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
@@ -57,13 +58,13 @@
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.doNothing
 import org.mockito.Mockito.nullable
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.MockitoAnnotations
 import java.util.Optional
 
 @SmallTest
@@ -93,8 +94,6 @@
     private lateinit var serviceInfo: ControlsServiceInfo
     @Mock
     private lateinit var uiEventLogger: UiEventLogger
-    @Mock
-    private lateinit var keyguardStateController: KeyguardStateController
     @Captor
     private lateinit var listingCallbackCaptor:
             ArgumentCaptor<ControlsListingController.ControlsListingCallback>
@@ -119,7 +118,6 @@
         `when`(qsHost.context).thenReturn(spiedContext)
         `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
         `when`(controlsComponent.isEnabled()).thenReturn(true)
-        `when`(keyguardStateController.isUnlocked()).thenReturn(true)
         `when`(controlsController.getPreferredStructure())
                 .thenReturn(StructureInfo(ComponentName("pkg", "cls"), "structure", listOf()))
         secureSettings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 1)
@@ -222,12 +220,19 @@
     }
 
     @Test
-    fun testStateAvailableIfListings() {
+    fun testStateActiveIfListingsHasControlsFavorited() {
         verify(controlsListingController).observe(
                 any(LifecycleOwner::class.java),
                 capture(listingCallbackCaptor)
         )
         `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
+        `when`(controlsController.getPreferredStructure()).thenReturn(
+            StructureInfo(
+                ComponentName("pkg", "cls"),
+                "structure",
+                listOf(ControlInfo("id", "title", "subtitle", 1))
+            )
+        )
 
         listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
         testableLooper.processAllMessages()
@@ -236,6 +241,22 @@
     }
 
     @Test
+    fun testStateInactiveIfListingsHasNoControlsFavorited() {
+        verify(controlsListingController).observe(
+                any(LifecycleOwner::class.java),
+                capture(listingCallbackCaptor)
+        )
+        `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
+        `when`(controlsController.getPreferredStructure())
+                .thenReturn(StructureInfo(ComponentName("pkg", "cls"), "structure", listOf()))
+
+        listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
+        testableLooper.processAllMessages()
+
+        assertThat(tile.state.state).isEqualTo(Tile.STATE_INACTIVE)
+    }
+
+    @Test
     fun testStateInactiveIfLocked() {
         verify(controlsListingController).observe(
             any(LifecycleOwner::class.java),
@@ -281,7 +302,14 @@
                 capture(listingCallbackCaptor)
         )
         `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
-        `when`(keyguardStateController.isUnlocked).thenReturn(true)
+        `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
+        `when`(controlsController.getPreferredStructure()).thenReturn(
+            StructureInfo(
+                ComponentName("pkg", "cls"),
+                "structure",
+                listOf(ControlInfo("id", "title", "subtitle", 1))
+            )
+        )
 
         listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
         testableLooper.processAllMessages()
@@ -305,7 +333,14 @@
         )
         `when`(controlsComponent.getVisibility())
             .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
-        `when`(keyguardStateController.isUnlocked).thenReturn(false)
+        `when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
+        `when`(controlsController.getPreferredStructure()).thenReturn(
+            StructureInfo(
+                ComponentName("pkg", "cls"),
+                "structure",
+                listOf(ControlInfo("id", "title", "subtitle", 1))
+            )
+        )
 
         listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
         testableLooper.processAllMessages()
@@ -345,8 +380,7 @@
                 statusBarStateController,
                 activityStarter,
                 qsLogger,
-                controlsComponent,
-                keyguardStateController
+                controlsComponent
         ).also {
             it.initialize()
             testableLooper.processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
new file mode 100644
index 0000000..ea70c26
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles
+
+import android.app.UiModeManager
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.os.Handler
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.LocationController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class UiModeNightTileTest : SysuiTestCase() {
+
+    @Mock
+    private lateinit var mockContext: Context
+    @Mock
+    private lateinit var uiModeManager: UiModeManager
+    @Mock
+    private lateinit var resources: Resources
+    @Mock
+    private lateinit var qsLogger: QSLogger
+    @Mock
+    private lateinit var qsHost: QSTileHost
+    @Mock
+    private lateinit var metricsLogger: MetricsLogger
+    @Mock
+    private lateinit var statusBarStateController: StatusBarStateController
+    @Mock
+    private lateinit var activityStarter: ActivityStarter
+    @Mock
+    private lateinit var configurationController: ConfigurationController
+    @Mock
+    private lateinit var batteryController: BatteryController
+    @Mock
+    private lateinit var locationController: LocationController
+
+    private val uiEventLogger = UiEventLoggerFake()
+    private val falsingManager = FalsingManagerFake()
+    private lateinit var testableLooper: TestableLooper
+    private lateinit var tile: UiModeNightTile
+    private lateinit var configuration: Configuration
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
+        configuration = Configuration()
+        mContext.addMockSystemService(Context.UI_MODE_SERVICE, uiModeManager)
+
+        `when`(qsHost.context).thenReturn(mockContext)
+        `when`(qsHost.userContext).thenReturn(mContext)
+        `when`(mockContext.resources).thenReturn(resources)
+        `when`(resources.configuration).thenReturn(configuration)
+        `when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
+
+        tile = UiModeNightTile(
+                qsHost,
+                testableLooper.looper,
+                Handler(testableLooper.looper),
+                falsingManager,
+                metricsLogger,
+                statusBarStateController,
+                activityStarter,
+                qsLogger,
+                configurationController,
+                batteryController,
+                locationController)
+    }
+
+    @Test
+    fun testIcon_whenNightModeOn_isOnState() {
+        val state = QSTile.BooleanState()
+        setNightModeOn()
+
+        tile.handleUpdateState(state, /* arg= */ null)
+
+        assertThat(state.icon)
+                .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_light_dark_theme_icon_on))
+    }
+
+    @Test
+    fun testIcon_whenNightModeOn_isOffState() {
+        val state = QSTile.BooleanState()
+        setNightModeOff()
+
+        tile.handleUpdateState(state, /* arg= */ null)
+
+        assertThat(state.icon)
+                .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_light_dark_theme_icon_off))
+    }
+
+    private fun setNightModeOn() {
+        `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_YES)
+        configuration.uiMode = Configuration.UI_MODE_NIGHT_YES
+    }
+
+    private fun setNightModeOff() {
+        `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_NO)
+        configuration.uiMode = Configuration.UI_MODE_NIGHT_NO
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index 5db3b9c..da52a9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -53,7 +53,6 @@
     @Mock private lateinit var mUserDetailItemView: UserDetailItemView
     @Mock private lateinit var mOtherView: View
     @Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
-    @Mock private lateinit var mUserInfo: UserInfo
     @Mock private lateinit var mLayoutInflater: LayoutInflater
     private var falsingManagerFake: FalsingManagerFake = FalsingManagerFake()
     private lateinit var adapter: UserDetailView.Adapter
@@ -142,7 +141,7 @@
 
     private fun createUserRecord(current: Boolean, guest: Boolean) =
         UserRecord(
-            mUserInfo,
+            UserInfo(0 /* id */, "name", 0 /* flags */),
             mPicture,
             guest,
             current,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
index 00f3808..5a4bafc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
@@ -23,7 +23,7 @@
 import android.os.IBinder
 import android.testing.AndroidTestingRunner
 import android.view.Display
-import android.view.SurfaceControl.ScreenshotHardwareBuffer
+import android.window.ScreenCapture.ScreenshotHardwareBuffer
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
@@ -84,7 +84,12 @@
             this.width = width
             this.height = height
             this.crop = crop
-            return ScreenshotHardwareBuffer(null, null, false, false)
+            return ScreenshotHardwareBuffer(
+                null,
+                null,
+                false,
+                false
+            )
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
index e85ffb6..c448538 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -23,6 +23,7 @@
 import android.testing.AndroidTestingRunner
 import android.view.DisplayCutout
 import android.view.View
+import android.view.ViewPropertyAnimator
 import android.view.WindowInsets
 import android.widget.TextView
 import androidx.constraintlayout.motion.widget.MotionLayout
@@ -30,6 +31,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
@@ -64,6 +66,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers
 import org.mockito.Mock
+import org.mockito.Mockito
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyFloat
 import org.mockito.Mockito.anyInt
@@ -614,6 +617,34 @@
         )
     }
 
+    @Test
+    fun animateOutOnStartCustomizing() {
+        val animator = Mockito.mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+        val duration = 1000L
+        whenever(view.animate()).thenReturn(animator)
+
+        controller.startCustomizingAnimation(show = true, duration)
+
+        verify(animator).setDuration(duration)
+        verify(animator).alpha(0f)
+        verify(animator).setInterpolator(Interpolators.ALPHA_OUT)
+        verify(animator).start()
+    }
+
+    @Test
+    fun animateInOnEndCustomizing() {
+        val animator = Mockito.mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+        val duration = 1000L
+        whenever(view.animate()).thenReturn(animator)
+
+        controller.startCustomizingAnimation(show = false, duration)
+
+        verify(animator).setDuration(duration)
+        verify(animator).alpha(1f)
+        verify(animator).setInterpolator(Interpolators.ALPHA_IN)
+        verify(animator).start()
+    }
+
     private fun createWindowInsets(
         topCutout: Rect? = Rect()
     ): WindowInsets {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index 8511443..5ecfc8eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -4,10 +4,12 @@
 import android.content.Context
 import android.testing.AndroidTestingRunner
 import android.view.View
+import android.view.ViewPropertyAnimator
 import android.widget.TextView
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
@@ -29,8 +31,10 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Answers
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.Mockito.`when` as whenever
@@ -198,4 +202,32 @@
                 context.getString(com.android.internal.R.string.status_bar_alarm_clock)
         )
     }
+
+    @Test
+    fun animateOutOnStartCustomizing() {
+        val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+        val duration = 1000L
+        whenever(view.animate()).thenReturn(animator)
+
+        mLargeScreenShadeHeaderController.startCustomizingAnimation(show = true, duration)
+
+        verify(animator).setDuration(duration)
+        verify(animator).alpha(0f)
+        verify(animator).setInterpolator(Interpolators.ALPHA_OUT)
+        verify(animator).start()
+    }
+
+    @Test
+    fun animateInOnEndCustomizing() {
+        val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+        val duration = 1000L
+        whenever(view.animate()).thenReturn(animator)
+
+        mLargeScreenShadeHeaderController.startCustomizingAnimation(show = false, duration)
+
+        verify(animator).setDuration(duration)
+        verify(animator).alpha(1f)
+        verify(animator).setInterpolator(Interpolators.ALPHA_IN)
+        verify(animator).start()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index f267013..e730713 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -42,7 +42,6 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.IdRes;
-import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -57,6 +56,7 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewPropertyAnimator;
 import android.view.ViewStub;
@@ -107,6 +107,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
+import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.CommandQueue;
@@ -160,8 +161,6 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -184,226 +183,136 @@
 @TestableLooper.RunWithLooper
 public class NotificationPanelViewControllerTest extends SysuiTestCase {
 
+    private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
     private static final int NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE = 50;
+    private static final int PANEL_WIDTH = 500; // Random value just for the test.
 
-    @Mock
-    private CentralSurfaces mCentralSurfaces;
-    @Mock
-    private NotificationStackScrollLayout mNotificationStackScrollLayout;
-    @Mock
-    private KeyguardBottomAreaView mKeyguardBottomArea;
-    @Mock
-    private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
-    @Mock
-    private KeyguardBottomAreaView mQsFrame;
-    private KeyguardStatusView mKeyguardStatusView;
-    @Mock
-    private NotificationIconAreaController mNotificationAreaController;
-    @Mock
-    private HeadsUpManagerPhone mHeadsUpManager;
-    @Mock
-    private NotificationShelfController mNotificationShelfController;
-    @Mock
-    private KeyguardStatusBarView mKeyguardStatusBar;
-    @Mock
-    private KeyguardUserSwitcherView mUserSwitcherView;
-    @Mock
-    private ViewStub mUserSwitcherStubView;
-    @Mock
-    private HeadsUpTouchHelper.Callback mHeadsUpCallback;
-    @Mock
-    private KeyguardUpdateMonitor mUpdateMonitor;
-    @Mock
-    private KeyguardBypassController mKeyguardBypassController;
-    @Mock
-    private DozeParameters mDozeParameters;
-    @Mock
-    private ScreenOffAnimationController mScreenOffAnimationController;
-    @Mock
-    private NotificationPanelView mView;
-    @Mock
-    private LayoutInflater mLayoutInflater;
-    @Mock
-    private FeatureFlags mFeatureFlags;
-    @Mock
-    private DynamicPrivacyController mDynamicPrivacyController;
-    @Mock
-    private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
-    @Mock
-    private KeyguardStateController mKeyguardStateController;
-    @Mock
-    private DozeLog mDozeLog;
-    @Mock
-    private ShadeLogger mShadeLog;
-    @Mock
-    private CommandQueue mCommandQueue;
-    @Mock
-    private VibratorHelper mVibratorHelper;
-    @Mock
-    private LatencyTracker mLatencyTracker;
-    @Mock
-    private PowerManager mPowerManager;
-    @Mock
-    private AccessibilityManager mAccessibilityManager;
-    @Mock
-    private MetricsLogger mMetricsLogger;
-    @Mock
-    private ActivityManager mActivityManager;
-    @Mock
-    private Resources mResources;
-    @Mock
-    private Configuration mConfiguration;
-    private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-    @Mock
-    private KeyguardClockSwitch mKeyguardClockSwitch;
-    private NotificationPanelViewController.TouchHandler mTouchHandler;
-    private ConfigurationController mConfigurationController;
-    @Mock
-    private MediaHierarchyManager mMediaHiearchyManager;
-    @Mock
-    private ConversationNotificationManager mConversationNotificationManager;
-    @Mock
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    @Mock
-    private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
-    @Mock
-    private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
-    @Mock
-    private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
-    @Mock
-    private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
-    @Mock
-    private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
-    @Mock
-    private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
-    @Mock
-    private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
-    @Mock
-    private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
-    @Mock
-    private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
-    @Mock
-    private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
-    @Mock
-    private KeyguardClockSwitchController mKeyguardClockSwitchController;
-    @Mock
-    private KeyguardStatusViewController mKeyguardStatusViewController;
-    @Mock
-    private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
-    @Mock
-    private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
-    @Mock
-    private NotificationShadeDepthController mNotificationShadeDepthController;
-    @Mock
-    private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    @Mock
-    private AuthController mAuthController;
-    @Mock
-    private ScrimController mScrimController;
-    @Mock
-    private MediaDataManager mMediaDataManager;
-    @Mock
-    private AmbientState mAmbientState;
-    @Mock
-    private UserManager mUserManager;
-    @Mock
-    private UiEventLogger mUiEventLogger;
-    @Mock
-    private LockIconViewController mLockIconViewController;
-    @Mock
-    private KeyguardMediaController mKeyguardMediaController;
-    @Mock
-    private PrivacyDotViewController mPrivacyDotViewController;
-    @Mock
-    private NavigationModeController mNavigationModeController;
-    @Mock
-    private SecureSettings mSecureSettings;
-    @Mock
-    private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
-    @Mock
-    private ContentResolver mContentResolver;
-    @Mock
-    private TapAgainViewController mTapAgainViewController;
-    @Mock
-    private KeyguardIndicationController mKeyguardIndicationController;
-    @Mock
-    private FragmentService mFragmentService;
-    @Mock
-    private FragmentHostManager mFragmentHostManager;
-    @Mock
-    private QuickAccessWalletController mQuickAccessWalletController;
-    @Mock
-    private QRCodeScannerController mQrCodeScannerController;
-    @Mock
-    private NotificationRemoteInputManager mNotificationRemoteInputManager;
-    @Mock
-    private RecordingController mRecordingController;
-    @Mock
-    private ControlsComponent mControlsComponent;
-    @Mock
-    private LockscreenGestureLogger mLockscreenGestureLogger;
-    @Mock
-    private DumpManager mDumpManager;
-    @Mock
-    private InteractionJankMonitor mInteractionJankMonitor;
-    @Mock
-    private NotificationsQSContainerController mNotificationsQSContainerController;
-    @Mock
-    private QsFrameTranslateController mQsFrameTranslateController;
-    @Mock
-    private StatusBarWindowStateController mStatusBarWindowStateController;
-    @Mock
-    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
-    @Mock
-    private NotificationShadeWindowController mNotificationShadeWindowController;
-    @Mock
-    private SysUiState mSysUiState;
-    @Mock
-    private NotificationListContainer mNotificationListContainer;
-    @Mock
-    private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
-    @Mock
-    private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
-    @Mock
-    private ShadeTransitionController mShadeTransitionController;
-    @Mock
-    private QS mQs;
-    @Mock
-    private View mQsHeader;
-    @Mock
-    private ViewParent mViewParent;
-    @Mock
-    private ViewTreeObserver mViewTreeObserver;
+    @Mock private CentralSurfaces mCentralSurfaces;
+    @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
+    @Mock private KeyguardBottomAreaView mKeyguardBottomArea;
+    @Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
+    @Mock private KeyguardBottomAreaView mQsFrame;
+    @Mock private NotificationIconAreaController mNotificationAreaController;
+    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private NotificationShelfController mNotificationShelfController;
+    @Mock private KeyguardStatusBarView mKeyguardStatusBar;
+    @Mock private KeyguardUserSwitcherView mUserSwitcherView;
+    @Mock private ViewStub mUserSwitcherStubView;
+    @Mock private HeadsUpTouchHelper.Callback mHeadsUpCallback;
+    @Mock private KeyguardUpdateMonitor mUpdateMonitor;
+    @Mock private KeyguardBypassController mKeyguardBypassController;
+    @Mock private DozeParameters mDozeParameters;
+    @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+    @Mock private NotificationPanelView mView;
+    @Mock private LayoutInflater mLayoutInflater;
+    @Mock private FeatureFlags mFeatureFlags;
+    @Mock private DynamicPrivacyController mDynamicPrivacyController;
+    @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private DozeLog mDozeLog;
+    @Mock private ShadeLogger mShadeLog;
+    @Mock private CommandQueue mCommandQueue;
+    @Mock private VibratorHelper mVibratorHelper;
+    @Mock private LatencyTracker mLatencyTracker;
+    @Mock private PowerManager mPowerManager;
+    @Mock private AccessibilityManager mAccessibilityManager;
+    @Mock private MetricsLogger mMetricsLogger;
+    @Mock private Resources mResources;
+    @Mock private Configuration mConfiguration;
+    @Mock private KeyguardClockSwitch mKeyguardClockSwitch;
+    @Mock private MediaHierarchyManager mMediaHiearchyManager;
+    @Mock private ConversationNotificationManager mConversationNotificationManager;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+    @Mock private KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
+    @Mock private KeyguardQsUserSwitchComponent mKeyguardQsUserSwitchComponent;
+    @Mock private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
+    @Mock private KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
+    @Mock private KeyguardUserSwitcherComponent mKeyguardUserSwitcherComponent;
+    @Mock private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
+    @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
+    @Mock private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
+    @Mock private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
+    @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController;
+    @Mock private KeyguardStatusViewController mKeyguardStatusViewController;
+    @Mock private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
+    @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+    @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
+    @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+    @Mock private AuthController mAuthController;
+    @Mock private ScrimController mScrimController;
+    @Mock private MediaDataManager mMediaDataManager;
+    @Mock private AmbientState mAmbientState;
+    @Mock private UserManager mUserManager;
+    @Mock private UiEventLogger mUiEventLogger;
+    @Mock private LockIconViewController mLockIconViewController;
+    @Mock private KeyguardMediaController mKeyguardMediaController;
+    @Mock private PrivacyDotViewController mPrivacyDotViewController;
+    @Mock private NavigationModeController mNavigationModeController;
+    @Mock private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
+    @Mock private ContentResolver mContentResolver;
+    @Mock private TapAgainViewController mTapAgainViewController;
+    @Mock private KeyguardIndicationController mKeyguardIndicationController;
+    @Mock private FragmentService mFragmentService;
+    @Mock private FragmentHostManager mFragmentHostManager;
+    @Mock private QuickAccessWalletController mQuickAccessWalletController;
+    @Mock private QRCodeScannerController mQrCodeScannerController;
+    @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
+    @Mock private RecordingController mRecordingController;
+    @Mock private ControlsComponent mControlsComponent;
+    @Mock private LockscreenGestureLogger mLockscreenGestureLogger;
+    @Mock private DumpManager mDumpManager;
+    @Mock private InteractionJankMonitor mInteractionJankMonitor;
+    @Mock private NotificationsQSContainerController mNotificationsQSContainerController;
+    @Mock private QsFrameTranslateController mQsFrameTranslateController;
+    @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
+    @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+    @Mock private SysUiState mSysUiState;
+    @Mock private NotificationListContainer mNotificationListContainer;
+    @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+    @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock private ShadeTransitionController mShadeTransitionController;
+    @Mock private QS mQs;
+    @Mock private QSFragment mQSFragment;
+    @Mock private ViewGroup mQsHeader;
+    @Mock private ViewParent mViewParent;
+    @Mock private ViewTreeObserver mViewTreeObserver;
     @Mock private KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
     @Mock private KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
-    private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
-    private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+
+    private NotificationPanelViewController.TouchHandler mTouchHandler;
+    private ConfigurationController mConfigurationController;
     private SysuiStatusBarStateController mStatusBarStateController;
     private NotificationPanelViewController mNotificationPanelViewController;
     private View.AccessibilityDelegate mAccessibiltyDelegate;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
     private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
-    private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
-    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private Handler mMainHandler;
+    private View.OnLayoutChangeListener mLayoutChangeListener;
+
+    private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
+    private final Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
+    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     private final PanelExpansionStateManager mPanelExpansionStateManager =
             new PanelExpansionStateManager();
-    private SystemClock mSystemClock;
+    private FragmentHostManager.FragmentListener mFragmentListener;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mSystemClock = new FakeSystemClock();
+        SystemClock systemClock = new FakeSystemClock();
         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
                 mInteractionJankMonitor);
 
-        mKeyguardStatusView = new KeyguardStatusView(mContext);
-        mKeyguardStatusView.setId(R.id.keyguard_status_view);
+        KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
+        keyguardStatusView.setId(R.id.keyguard_status_view);
         DejankUtils.setImmediate(true);
 
         when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
         when(mHeadsUpCallback.getContext()).thenReturn(mContext);
         when(mView.getResources()).thenReturn(mResources);
+        when(mView.getWidth()).thenReturn(PANEL_WIDTH);
         when(mResources.getConfiguration()).thenReturn(mConfiguration);
         mConfiguration.orientation = ORIENTATION_PORTRAIT;
         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
@@ -413,6 +322,8 @@
                 .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
         when(mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal))
                 .thenReturn(10);
+        when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
+                .thenReturn(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
         when(mView.getContext()).thenReturn(getContext());
         when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
         when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
@@ -431,7 +342,7 @@
         when(mView.findViewById(R.id.keyguard_status_view))
                 .thenReturn(mock(KeyguardStatusView.class));
         mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
-        mNotificationContainerParent.addView(mKeyguardStatusView);
+        mNotificationContainerParent.addView(keyguardStatusView);
         mNotificationContainerParent.onFinishInflate();
         when(mView.findViewById(R.id.notification_container_parent))
                 .thenReturn(mNotificationContainerParent);
@@ -447,7 +358,12 @@
         when(mKeyguardUserSwitcherComponent.getKeyguardUserSwitcherController())
                 .thenReturn(mKeyguardUserSwitcherController);
         when(mScreenOffAnimationController.shouldAnimateClockChange()).thenReturn(true);
-
+        when(mQs.getView()).thenReturn(mView);
+        when(mQSFragment.getView()).thenReturn(mView);
+        doAnswer(invocation -> {
+            mFragmentListener = invocation.getArgument(1);
+            return null;
+        }).when(mFragmentHostManager).addTagListener(eq(QS.TAG), any());
         doAnswer((Answer<Void>) invocation -> {
             mTouchHandler = invocation.getArgument(0);
             return null;
@@ -484,7 +400,7 @@
         when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
                 .thenReturn(mKeyguardStatusBarViewController);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
-                .thenReturn(mKeyguardStatusView);
+                .thenReturn(keyguardStatusView);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
                 .thenReturn(mUserSwitcherView);
         when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
@@ -499,13 +415,18 @@
             ((Runnable) invocation.getArgument(0)).run();
             return null;
         }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
+        doAnswer(invocation -> {
+            mLayoutChangeListener = invocation.getArgument(0);
+            return null;
+        }).when(mView).addOnLayoutChangeListener(any());
 
         when(mView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
         when(mView.getParent()).thenReturn(mViewParent);
         when(mQs.getHeader()).thenReturn(mQsHeader);
 
         mMainHandler = new Handler(Looper.getMainLooper());
-        mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter();
+        NotificationPanelViewController.PanelEventsEmitter panelEventsEmitter =
+                new NotificationPanelViewController.PanelEventsEmitter();
 
         mNotificationPanelViewController = new NotificationPanelViewController(
                 mView,
@@ -547,8 +468,6 @@
                 mNavigationModeController,
                 mFragmentService,
                 mContentResolver,
-                mQuickAccessWalletController,
-                mQrCodeScannerController,
                 mRecordingController,
                 mLargeScreenShadeHeaderController,
                 mScreenOffAnimationController,
@@ -556,21 +475,20 @@
                 mPanelExpansionStateManager,
                 mNotificationRemoteInputManager,
                 mSysUIUnfoldComponent,
-                mControlsComponent,
                 mInteractionJankMonitor,
                 mQsFrameTranslateController,
                 mSysUiState,
                 () -> mKeyguardBottomAreaViewController,
                 mKeyguardUnlockAnimationController,
                 mNotificationListContainer,
-                mPanelEventsEmitter,
+                panelEventsEmitter,
                 mNotificationStackSizeCalculator,
                 mUnlockedScreenOffAnimationController,
                 mShadeTransitionController,
-                mSystemClock,
+                systemClock,
                 mock(CameraGestureHelper.class),
-                () -> mKeyguardBottomAreaViewModel,
-                () -> mKeyguardBottomAreaInteractor);
+                mKeyguardBottomAreaViewModel,
+                mKeyguardBottomAreaInteractor);
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
                 () -> {},
@@ -751,8 +669,9 @@
     }
 
     @Test
-    public void testSetPanelScrimMinFraction() {
-        mNotificationPanelViewController.setPanelScrimMinFraction(0.5f);
+    public void testSetPanelScrimMinFractionWhenHeadsUpIsDragged() {
+        mNotificationPanelViewController.setHeadsUpDraggingStartingHeight(
+                mNotificationPanelViewController.getMaxPanelHeight() / 2);
         verify(mNotificationShadeDepthController).setPanelPullDownMinFraction(eq(0.5f));
     }
 
@@ -1448,40 +1367,137 @@
     }
 
     @Test
-    public void getMaxPanelHeight_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() {
-        int splitShadeFullTransitionDistance = 123456;
+    public void getMaxPanelTransitionDistance_expanding_inSplitShade_returnsSplitShadeFullTransitionDistance() {
         enableSplitShade(true);
-        setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
         mNotificationPanelViewController.expandWithQs();
 
-        int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
+        int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
 
-        assertThat(maxPanelHeight).isEqualTo(splitShadeFullTransitionDistance);
+        assertThat(maxDistance).isEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
     }
 
     @Test
-    public void getMaxPanelHeight_expandingSplitShade_keyguard_returnsNonSplitShadeValue() {
+    public void getMaxPanelTransitionDistance_inSplitShade_withHeadsUp_returnsBiggerValue() {
+        enableSplitShade(true);
+        mNotificationPanelViewController.expandWithQs();
+        when(mHeadsUpManager.isTrackingHeadsUp()).thenReturn(true);
+        mNotificationPanelViewController.setHeadsUpDraggingStartingHeight(
+                SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+
+        int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
+
+        assertThat(maxDistance).isGreaterThan(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+    }
+
+    @Test
+    public void getMaxPanelTransitionDistance_expandingSplitShade_keyguard_returnsNonSplitShadeValue() {
         mStatusBarStateController.setState(KEYGUARD);
-        int splitShadeFullTransitionDistance = 123456;
         enableSplitShade(true);
-        setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
         mNotificationPanelViewController.expandWithQs();
 
-        int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
+        int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
 
-        assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
+        assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
     }
 
     @Test
-    public void getMaxPanelHeight_expanding_notSplitShade_returnsNonSplitShadeValue() {
-        int splitShadeFullTransitionDistance = 123456;
+    public void getMaxPanelTransitionDistance_expanding_notSplitShade_returnsNonSplitShadeValue() {
         enableSplitShade(false);
-        setSplitShadeFullTransitionDistance(splitShadeFullTransitionDistance);
         mNotificationPanelViewController.expandWithQs();
 
-        int maxPanelHeight = mNotificationPanelViewController.getMaxPanelHeight();
+        int maxDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
 
-        assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
+        assertThat(maxDistance).isNotEqualTo(SPLIT_SHADE_FULL_TRANSITION_DISTANCE);
+    }
+
+    @Test
+    public void onLayoutChange_fullWidth_updatesQSWithFullWithTrue() {
+        mNotificationPanelViewController.mQs = mQs;
+
+        setIsFullWidth(true);
+
+        verify(mQs).setIsNotificationPanelFullWidth(true);
+    }
+
+    @Test
+    public void onLayoutChange_notFullWidth_updatesQSWithFullWithFalse() {
+        mNotificationPanelViewController.mQs = mQs;
+
+        setIsFullWidth(false);
+
+        verify(mQs).setIsNotificationPanelFullWidth(false);
+    }
+
+    @Test
+    public void onLayoutChange_qsNotSet_doesNotCrash() {
+        mNotificationPanelViewController.mQs = null;
+
+        triggerLayoutChange();
+    }
+
+    @Test
+    public void onQsFragmentAttached_fullWidth_setsFullWidthTrueOnQS() {
+        setIsFullWidth(true);
+        givenViewAttached();
+        mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment);
+
+        verify(mQSFragment).setIsNotificationPanelFullWidth(true);
+    }
+
+    @Test
+    public void onQsFragmentAttached_notFullWidth_setsFullWidthFalseOnQS() {
+        setIsFullWidth(false);
+        givenViewAttached();
+        mFragmentListener.onFragmentViewCreated(QS.TAG, mQSFragment);
+
+        verify(mQSFragment).setIsNotificationPanelFullWidth(false);
+    }
+
+    @Test
+    public void setQsExpansion_lockscreenShadeTransitionInProgress_usesLockscreenSquishiness() {
+        float squishinessFraction = 0.456f;
+        mNotificationPanelViewController.mQs = mQs;
+        when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
+                .thenReturn(squishinessFraction);
+        when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
+                .thenReturn(0.987f);
+        // Call setTransitionToFullShadeAmount to get into the full shade transition in progress
+        // state.
+        mNotificationPanelViewController.setTransitionToFullShadeAmount(
+                /* pxAmount= */ 234,
+                /* animate= */ false,
+                /* delay= */ 0
+        );
+
+        mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+
+        // First for setTransitionToFullShadeAmount and then setQsExpansion
+        verify(mQs, times(2)).setQsExpansion(
+                /* expansion= */ anyFloat(),
+                /* panelExpansionFraction= */ anyFloat(),
+                /* proposedTranslation= */ anyFloat(),
+                eq(squishinessFraction)
+        );
+    }
+
+    @Test
+    public void setQsExpansion_lockscreenShadeTransitionNotInProgress_usesStandardSquishiness() {
+        float lsSquishinessFraction = 0.456f;
+        float nsslSquishinessFraction = 0.987f;
+        mNotificationPanelViewController.mQs = mQs;
+        when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
+                .thenReturn(lsSquishinessFraction);
+        when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
+                .thenReturn(nsslSquishinessFraction);
+
+        mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+
+        verify(mQs).setQsExpansion(
+                /* expansion= */ anyFloat(),
+                /* panelExpansionFraction= */ anyFloat(),
+                /* proposedTranslation= */ anyFloat(),
+                eq(nsslSquishinessFraction)
+        );
     }
 
     private static MotionEvent createMotionEvent(int x, int y, int action) {
@@ -1507,12 +1523,6 @@
         }
     }
 
-    private void givenViewDetached() {
-        for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
-            listener.onViewDetachedFromWindow(mView);
-        }
-    }
-
     private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
         ConstraintSet constraintSet = new ConstraintSet();
         constraintSet.clone(mNotificationContainerParent);
@@ -1544,12 +1554,6 @@
         mTouchHandler.onTouch(mView, ev);
     }
 
-    private void setSplitShadeFullTransitionDistance(int splitShadeFullTransitionDistance) {
-        when(mResources.getDimensionPixelSize(R.dimen.split_shade_full_transition_distance))
-                .thenReturn(splitShadeFullTransitionDistance);
-        mNotificationPanelViewController.updateResources();
-    }
-
     private void setDozing(boolean dozing, boolean dozingAlwaysOn) {
         when(mDozeParameters.getAlwaysOn()).thenReturn(dozingAlwaysOn);
         mNotificationPanelViewController.setDozing(
@@ -1569,4 +1573,24 @@
         assertThat(getConstraintSetLayout(R.id.keyguard_status_view).endToEnd).isEqualTo(
                 R.id.qs_edge_guideline);
     }
+
+    private void setIsFullWidth(boolean fullWidth) {
+        float nsslWidth = fullWidth ? PANEL_WIDTH : PANEL_WIDTH / 2f;
+        when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(nsslWidth);
+        triggerLayoutChange();
+    }
+
+    private void triggerLayoutChange() {
+        mLayoutChangeListener.onLayoutChange(
+                mView,
+                /* left= */ 0,
+                /* top= */ 0,
+                /* right= */ 0,
+                /* bottom= */ 0,
+                /* oldLeft= */ 0,
+                /* oldTop= */ 0,
+                /* oldRight= */ 0,
+                /* oldBottom= */ 0
+        );
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
index 0c6a6a9..12ef036 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -33,10 +34,10 @@
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import java.util.function.Consumer
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -63,6 +64,8 @@
     @Mock
     private lateinit var notificationsQSContainer: NotificationsQuickSettingsContainer
     @Mock
+    private lateinit var largeScreenShadeHeaderController: LargeScreenShadeHeaderController
+    @Mock
     private lateinit var featureFlags: FeatureFlags
     @Captor
     lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener>
@@ -92,6 +95,7 @@
                 notificationsQSContainer,
                 navigationModeController,
                 overviewProxyService,
+                largeScreenShadeHeaderController,
                 featureFlags,
                 delayableExecutor
         )
@@ -371,8 +375,14 @@
         container.removeAllViews()
         container.addView(newViewWithId(1))
         container.addView(newViewWithId(View.NO_ID))
-        val controller = NotificationsQSContainerController(container, navigationModeController,
-                overviewProxyService, featureFlags, delayableExecutor)
+        val controller = NotificationsQSContainerController(
+                container,
+                navigationModeController,
+                overviewProxyService,
+                largeScreenShadeHeaderController,
+                featureFlags,
+                delayableExecutor
+        )
         controller.updateConstraints()
 
         assertThat(container.getChildAt(0).id).isEqualTo(1)
@@ -397,6 +407,21 @@
         verify(notificationsQSContainer).setQSContainerPaddingBottom(STABLE_INSET_BOTTOM)
     }
 
+    @Test
+    fun testStartCustomizingWithDuration() {
+        controller.setCustomizerShowing(true, 100L)
+        verify(largeScreenShadeHeaderController).startCustomizingAnimation(true, 100L)
+    }
+
+    @Test
+    fun testEndCustomizingWithDuration() {
+        controller.setCustomizerShowing(true, 0L) // Only tracks changes
+        reset(largeScreenShadeHeaderController)
+
+        controller.setCustomizerShowing(false, 100L)
+        verify(largeScreenShadeHeaderController).startCustomizingAnimation(false, 100L)
+    }
+
     private fun disableSplitShade() {
         setSplitShadeEnabled(false)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 43fc8983..2adc389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -19,8 +19,10 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.MotionEvent
+import android.view.ViewGroup
 import androidx.test.filters.SmallTest
 import com.android.keyguard.LockIconViewController
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.dock.DockManager
@@ -246,6 +248,18 @@
         verify(phoneStatusBarViewController).sendTouchToView(nextEvent)
         assertThat(returnVal).isTrue()
     }
+
+    @Test
+    fun testGetBouncerContainer() {
+        underTest.bouncerContainer
+        verify(view).findViewById<ViewGroup>(R.id.keyguard_bouncer_container)
+    }
+
+    @Test
+    fun testGetKeyguardMessageArea() {
+        underTest.keyguardMessageArea
+        verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
+    }
 }
 
 private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index d2970a6..97c0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.tuner.TunerService.Tunable
@@ -63,6 +64,8 @@
     private lateinit var tunerService: TunerService
     @Mock
     private lateinit var dumpManager: DumpManager
+    @Mock
+    private lateinit var statusBarStateController: StatusBarStateController
 
     private lateinit var tunableCaptor: ArgumentCaptor<Tunable>
     private lateinit var underTest: PulsingGestureListener
@@ -77,6 +80,7 @@
                 dockManager,
                 centralSurfaces,
                 ambientDisplayConfiguration,
+                statusBarStateController,
                 tunerService,
                 dumpManager
         )
@@ -85,6 +89,8 @@
 
     @Test
     fun testGestureDetector_singleTapEnabled() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -102,6 +108,8 @@
 
     @Test
     fun testGestureDetector_doubleTapEnabled() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN double tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -119,6 +127,8 @@
 
     @Test
     fun testGestureDetector_singleTapEnabled_falsing() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -135,7 +145,23 @@
     }
 
     @Test
+    fun testGestureDetector_notPulsing_noFalsingCheck() {
+        whenever(statusBarStateController.isPulsing).thenReturn(false)
+
+        // GIVEN tap is enabled, prox not covered
+        whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
+        // WHEN there's a tap
+        underTest.onSingleTapConfirmed(downEv)
+
+        // THEN the falsing manager never gets a call (because the device wasn't pulsing
+        // during the tap)
+        verify(falsingManager, never()).isFalseTap(anyInt())
+    }
+
+    @Test
     fun testGestureDetector_doubleTapEnabled_falsing() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN double tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -153,6 +179,8 @@
 
     @Test
     fun testGestureDetector_singleTapEnabled_proxCovered() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN tap is enabled, not a false tap based on classifiers
         whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -170,6 +198,8 @@
 
     @Test
     fun testGestureDetector_doubleTapEnabled_proxCovered() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN double tap is enabled, not a false tap based on classifiers
         whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index baaa447..6be76a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -13,6 +13,7 @@
 import com.android.systemui.statusbar.phone.panelstate.STATE_OPEN
 import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
 import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -28,6 +29,7 @@
     @Mock private lateinit var scrimController: ScrimController
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+    @Mock private lateinit var headsUpManager: HeadsUpManager
     private val configurationController = FakeConfigurationController()
 
     private lateinit var controller: ScrimShadeTransitionController
@@ -42,7 +44,8 @@
                 dumpManager,
                 scrimController,
                 context.resources,
-                statusBarStateController)
+                statusBarStateController,
+                headsUpManager)
 
         controller.onPanelStateChanged(STATE_OPENING)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
new file mode 100644
index 0000000..d925d0a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.ExpandHelper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DragDownHelperTest : SysuiTestCase() {
+
+    private lateinit var dragDownHelper: DragDownHelper
+
+    private val collapsedHeight = 300
+    private val falsingManager: FalsingManager = mock()
+    private val falsingCollector: FalsingCollector = mock()
+    private val dragDownloadCallback: LockscreenShadeTransitionController = mock()
+    private val expandableView: ExpandableView = mock()
+    private val expandCallback: ExpandHelper.Callback = mock()
+
+    @Before
+    fun setUp() {
+        whenever(expandableView.collapsedHeight).thenReturn(collapsedHeight)
+
+        dragDownHelper = DragDownHelper(
+                falsingManager,
+                falsingCollector,
+                dragDownloadCallback,
+                mContext
+        ).also {
+            it.expandCallback = expandCallback
+        }
+    }
+
+    @Test
+    fun cancelChildExpansion_updateHeight() {
+        whenever(expandableView.actualHeight).thenReturn(500)
+
+        dragDownHelper.cancelChildExpansion(expandableView, animationDuration = 0)
+
+        verify(expandableView, atLeast(1)).actualHeight = collapsedHeight
+    }
+
+    @Test
+    fun cancelChildExpansion_dontUpdateHeight() {
+        whenever(expandableView.actualHeight).thenReturn(collapsedHeight)
+
+        dragDownHelper.cancelChildExpansion(expandableView, animationDuration = 0)
+
+        verify(expandableView, never()).actualHeight = anyInt()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 05692b3..464dfe2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -19,7 +19,10 @@
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
 
+import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
@@ -65,7 +68,6 @@
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.BatteryManager;
 import android.os.Looper;
@@ -86,6 +88,7 @@
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.FaceHelpMessageDeferral;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardIndication;
@@ -167,6 +170,8 @@
     @Mock
     private AccessibilityManager mAccessibilityManager;
     @Mock
+    private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
+    @Mock
     private ScreenLifecycle mScreenLifecycle;
     @Captor
     private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@@ -259,7 +264,8 @@
                 mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
                 mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
                 mUserManager, mExecutor, mExecutor,  mFalsingManager, mLockPatternUtils,
-                mScreenLifecycle, mKeyguardBypassController, mAccessibilityManager);
+                mScreenLifecycle, mKeyguardBypassController, mAccessibilityManager,
+                mFaceHelpMessageDeferral);
         mController.init();
         mController.setIndicationArea(mIndicationArea);
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
@@ -535,7 +541,7 @@
 
         mController.setVisible(true);
         mController.getKeyguardCallback().onBiometricHelp(
-                KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
+                BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
                 BiometricSourceType.FACE);
         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
         reset(mRotateTextViewController);
@@ -582,7 +588,7 @@
 
         // WHEN there's a face not recognized message
         mController.getKeyguardCallback().onBiometricHelp(
-                KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
+                BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
                 message,
                 BiometricSourceType.FACE);
 
@@ -602,7 +608,7 @@
         String message = mContext.getString(R.string.keyguard_unlock);
 
         mController.setVisible(true);
-        mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+        mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
                 "A message", BiometricSourceType.FACE);
 
         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
@@ -636,10 +642,10 @@
         when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
 
         mController.setVisible(true);
-        mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+        mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
                 "A message", BiometricSourceType.FACE);
 
-        verify(mStatusBarKeyguardViewManager).showBouncerMessage(eq(message), any());
+        verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any());
     }
 
     @Test
@@ -651,7 +657,7 @@
 
         mController.setVisible(true);
         mController.getKeyguardCallback().onBiometricError(
-                FaceManager.FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
+                FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
     }
 
@@ -698,8 +704,7 @@
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
         };
         for (int msgId : msgIds) {
             mKeyguardUpdateMonitorCallback.onBiometricHelp(
@@ -728,8 +733,7 @@
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
         };
         for (int msgId : msgIds) {
             final String numberedHelpString = helpString + msgId;
@@ -743,6 +747,68 @@
     }
 
     @Test
+    public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() {
+        createController();
+
+        // GIVEN fingerprint NOT enrolled
+        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+                0)).thenReturn(false);
+
+        // WHEN help message received and deferred message is valid
+        final String helpString = "helpMsg";
+        when(mFaceHelpMessageDeferral.getDeferredMessage()).thenReturn(helpString);
+        when(mFaceHelpMessageDeferral.shouldDefer(FACE_ACQUIRED_TOO_DARK)).thenReturn(true);
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+                helpString,
+                BiometricSourceType.FACE
+        );
+
+        // THEN help message not shown yet
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+        // WHEN face timeout error received
+        mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+                BiometricSourceType.FACE);
+
+        // THEN the low light message shows with suggestion to swipe up to unlock
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+                mContext.getString(R.string.keyguard_unlock));
+    }
+
+    @Test
+    public void sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled() {
+        createController();
+
+        // GIVEN fingerprint enrolled
+        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+                0)).thenReturn(true);
+
+        // WHEN help message received and deferredMessage is valid
+        final String helpString = "helpMsg";
+        when(mFaceHelpMessageDeferral.getDeferredMessage()).thenReturn(helpString);
+        when(mFaceHelpMessageDeferral.shouldDefer(FACE_ACQUIRED_TOO_DARK)).thenReturn(true);
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+                helpString,
+                BiometricSourceType.FACE
+        );
+
+        // THEN help message not shown yet
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+        // WHEN face timeout error received
+        mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+                BiometricSourceType.FACE);
+
+        // THEN the low light message shows and suggests trying fingerprint
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+                mContext.getString(R.string.keyguard_suggest_fingerprint));
+    }
+
+    @Test
     public void updateMonitor_listenerUpdatesIndication() {
         createController();
         String restingIndication = "Resting indication";
@@ -997,14 +1063,14 @@
     }
 
     @Test
-    public void onTrustGrantedMessageDoesShowsOnTrustGranted() {
+    public void onTrustGrantedMessageShowsOnTrustGranted() {
         createController();
         mController.setVisible(true);
 
         // GIVEN trust is granted
         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
 
-        // WHEN the showTrustGranted message is called
+        // WHEN the showTrustGranted method is called
         final String trustGrantedMsg = "testing trust granted message";
         mController.getKeyguardCallback().showTrustGrantedMessage(trustGrantedMsg);
 
@@ -1015,6 +1081,38 @@
     }
 
     @Test
+    public void onTrustGrantedMessage_nullMessage_showsDefaultMessage() {
+        createController();
+        mController.setVisible(true);
+
+        // GIVEN trust is granted
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+        // WHEN the showTrustGranted method is called with a null message
+        mController.getKeyguardCallback().showTrustGrantedMessage(null);
+
+        // THEN verify the default trust granted message shows
+        verifyIndicationMessage(
+                INDICATION_TYPE_TRUST,
+                getContext().getString(R.string.keyguard_indication_trust_unlocked));
+    }
+
+    @Test
+    public void onTrustGrantedMessage_emptyString_showsNoMessage() {
+        createController();
+        mController.setVisible(true);
+
+        // GIVEN trust is granted
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+        // WHEN the showTrustGranted method is called with an EMPTY string
+        mController.getKeyguardCallback().showTrustGrantedMessage("");
+
+        // THEN verify NO trust message is shown
+        verifyNoMessage(INDICATION_TYPE_TRUST);
+    }
+
+    @Test
     public void coEx_faceSuccess_showsPressToOpen() {
         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, no a11y enabled
         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
@@ -1038,7 +1136,6 @@
         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, pressToOpen);
     }
 
-
     @Test
     public void coEx_faceSuccess_touchExplorationEnabled_showsFaceUnlockedSwipeToOpen() {
         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y enabled
@@ -1184,6 +1281,87 @@
         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen);
     }
 
+    @Test
+    public void faceOnAcquired_processFrame() {
+        createController();
+
+        // WHEN face sends an acquired message
+        final int acquireInfo = 1;
+        mKeyguardUpdateMonitorCallback.onBiometricAcquired(BiometricSourceType.FACE, acquireInfo);
+
+        // THEN face help message deferral should process the acquired frame
+        verify(mFaceHelpMessageDeferral).processFrame(acquireInfo);
+    }
+
+    @Test
+    public void fingerprintOnAcquired_noProcessFrame() {
+        createController();
+
+        // WHEN fingerprint sends an acquired message
+        mKeyguardUpdateMonitorCallback.onBiometricAcquired(BiometricSourceType.FINGERPRINT, 1);
+
+        // THEN face help message deferral should NOT process any acquired frames
+        verify(mFaceHelpMessageDeferral, never()).processFrame(anyInt());
+    }
+
+    @Test
+    public void onBiometricHelp_fingerprint_faceHelpMessageDeferralDoesNothing() {
+        createController();
+
+        // WHEN fingerprint sends an onBiometricHelp
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                1,
+                "placeholder",
+                BiometricSourceType.FINGERPRINT);
+
+        // THEN face help message deferral is NOT: reset, updated, or checked for shouldDefer
+        verify(mFaceHelpMessageDeferral, never()).reset();
+        verify(mFaceHelpMessageDeferral, never()).updateMessage(anyInt(), anyString());
+        verify(mFaceHelpMessageDeferral, never()).shouldDefer(anyInt());
+    }
+
+    @Test
+    public void onBiometricFailed_resetFaceHelpMessageDeferral() {
+        createController();
+
+        // WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
+        mKeyguardUpdateMonitorCallback.onBiometricAuthFailed(BiometricSourceType.FACE);
+
+        // THEN face help message deferral is reset
+        verify(mFaceHelpMessageDeferral).reset();
+    }
+
+    @Test
+    public void onBiometricError_resetFaceHelpMessageDeferral() {
+        createController();
+
+        // WHEN face has an error
+        mKeyguardUpdateMonitorCallback.onBiometricError(4, "string",
+                BiometricSourceType.FACE);
+
+        // THEN face help message deferral is reset
+        verify(mFaceHelpMessageDeferral).reset();
+    }
+
+    @Test
+    public void onBiometricHelp_faceAcquiredInfo_faceHelpMessageDeferral() {
+        createController();
+
+        // WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
+        final int msgId = 1;
+        final String helpString = "test";
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                msgId,
+                "test",
+                BiometricSourceType.FACE);
+
+        // THEN face help message deferral is NOT reset and message IS updated
+        verify(mFaceHelpMessageDeferral, never()).reset();
+        verify(mFaceHelpMessageDeferral).updateMessage(msgId, helpString);
+    }
+
+
+
     private void sendUpdateDisclosureBroadcast() {
         mBroadcastReceiver.onReceive(mContext, new Intent());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
new file mode 100644
index 0000000..7041262
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.google.common.truth.Expect
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class LockscreenShadeQsTransitionControllerTest : SysuiTestCase() {
+
+    private val configurationController = FakeConfigurationController()
+
+    @get:Rule val expect: Expect = Expect.create()
+
+    @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var qS: QS
+
+    private lateinit var controller: LockscreenShadeQsTransitionController
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        setTransitionDistance(TRANSITION_DISTANCE)
+        setTransitionDelay(TRANSITION_DELAY)
+        setSquishTransitionDistance(SQUISH_TRANSITION_DISTANCE)
+        setSquishStartFraction(SQUISH_START_FRACTION)
+
+        controller =
+            LockscreenShadeQsTransitionController(
+                context,
+                configurationController,
+                dumpManager,
+                qsProvider = { qS }
+            )
+    }
+
+    @Test
+    fun qsTransitionFraction_byDefault_returns0() {
+        assertThat(controller.qsTransitionFraction).isZero()
+    }
+
+    @Test
+    fun qsTransitionFraction_noStartDelay_returnsBasedOnTransitionDistance() {
+        setTransitionDelay(0)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = 25f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.25f)
+
+        controller.dragDownAmount = 50f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 75f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.75f)
+
+        controller.dragDownAmount = 100f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsTransitionFraction_noStartDelay_returnsValuesBetween0and1() {
+        setTransitionDelay(0)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = -500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsTransitionFraction_withStartDelay_returnsBasedOnTransitionDistanceAndDelay() {
+        setTransitionDelay(10)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = 0f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 10f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 25f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.15f)
+
+        controller.dragDownAmount = 100f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0.9f)
+
+        controller.dragDownAmount = 110f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsTransitionFraction_withStartDelay_returnsValuesBetween0and1() {
+        setTransitionDelay(10)
+        setTransitionDistance(100)
+
+        controller.dragDownAmount = -500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(0f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_byDefault_returnsValueSetFromResource() {
+        assertThat(controller.qsSquishTransitionFraction).isEqualTo(SQUISH_START_FRACTION)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_noStartDelay_startFraction0_returnsBasedOnTransitionDistance() {
+        setTransitionDelay(0)
+        setSquishStartFraction(0f)
+        setSquishTransitionDistance(1000)
+
+        controller.dragDownAmount = 250f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.25f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 750f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f)
+
+        controller.dragDownAmount = 1000f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_startDelay_startFraction0_basedOnTransitionDistanceAndDelay() {
+        setTransitionDelay(100)
+        setSquishStartFraction(0f)
+        setSquishTransitionDistance(1000)
+
+        controller.dragDownAmount = 250f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.15f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.4f)
+
+        controller.dragDownAmount = 750f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.65f)
+
+        controller.dragDownAmount = 1000f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.9f)
+
+        controller.dragDownAmount = 1100f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_noStartDelay_startFractionSet_returnsBasedOnStartAndDistance() {
+        setTransitionDelay(0)
+        setSquishStartFraction(0.5f)
+        setSquishTransitionDistance(1000)
+
+        controller.dragDownAmount = 0f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 500f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.75f)
+
+        controller.dragDownAmount = 1000f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun qsSquishTransitionFraction_startDelay_startFractionSet_basedOnStartAndDistanceAndDelay() {
+        setTransitionDelay(10)
+        setSquishStartFraction(0.5f)
+        setSquishTransitionDistance(100)
+
+        controller.dragDownAmount = 0f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.5f)
+
+        controller.dragDownAmount = 50f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.7f)
+
+        controller.dragDownAmount = 100f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(0.95f)
+
+        controller.dragDownAmount = 110f
+        expect.that(controller.qsSquishTransitionFraction).isEqualTo(1f)
+    }
+
+    @Test
+    fun onDragDownAmountChanged_setsValuesOnQS() {
+        val rawDragAmount = 200f
+
+        controller.dragDownAmount = rawDragAmount
+
+        verify(qS)
+            .setTransitionToFullShadeProgress(
+                /* isTransitioningToFullShade= */ true,
+                /* transitionFraction= */ controller.qsTransitionFraction,
+                /* squishinessFraction= */ controller.qsSquishTransitionFraction
+            )
+    }
+
+    private fun setTransitionDistance(value: Int) {
+        overrideResource(R.dimen.lockscreen_shade_qs_transition_distance, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun setTransitionDelay(value: Int) {
+        overrideResource(R.dimen.lockscreen_shade_qs_transition_delay, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun setSquishTransitionDistance(value: Int) {
+        overrideResource(R.dimen.lockscreen_shade_qs_squish_transition_distance, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    private fun setSquishStartFraction(value: Float) {
+        overrideResource(R.dimen.lockscreen_shade_qs_squish_start_fraction, value)
+        configurationController.notifyConfigurationChanged()
+    }
+
+    companion object {
+        private const val TRANSITION_DELAY = 123
+        private const val TRANSITION_DISTANCE = 321
+        private const val SQUISH_START_FRACTION = 0.123f
+        private const val SQUISH_TRANSITION_DISTANCE = 456
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index fe1cd97..8643e86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,9 +1,9 @@
 package com.android.systemui.statusbar
 
-import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
 import com.android.systemui.ExpandHelper
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
@@ -78,6 +78,7 @@
     @Mock lateinit var qS: QS
     @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller
     @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller
+    @Mock lateinit var qsTransitionController: LockscreenShadeQsTransitionController
     @JvmField @Rule val mockito = MockitoJUnit.rule()
 
     private val configurationController = FakeConfigurationController()
@@ -120,7 +121,9 @@
                         context,
                         configurationController,
                         dumpManager)
-                })
+                },
+                qsTransitionControllerFactory = { qsTransitionController },
+            )
         whenever(nsslController.view).thenReturn(stackscroller)
         whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback)
         transitionController.notificationPanelController = notificationPanelController
@@ -249,7 +252,7 @@
         verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
                 anyBoolean(), anyLong())
-        verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+        verify(qsTransitionController, never()).dragDownAmount = anyFloat()
     }
 
     @Test
@@ -260,7 +263,7 @@
         verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
         verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
                 anyBoolean(), anyLong())
-        verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
+        verify(qsTransitionController).dragDownAmount = 10f
         verify(depthController).transitionToFullShadeProgress = anyFloat()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index b166b73..6446fb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -48,7 +48,6 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.any
 import org.mockito.Mockito.anyFloat
 import org.mockito.Mockito.anyString
@@ -56,6 +55,7 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
 
 @RunWith(AndroidTestingRunner::class)
@@ -139,7 +139,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(maxBlur), any())
+        verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
     @Test
@@ -147,7 +147,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 0.01f, expanded = false, tracking = false, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(maxBlur), any())
+        verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
     @Test
@@ -157,7 +157,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 0f, expanded = false, tracking = false, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(0), any())
+        verify(shadeAnimation).animateTo(eq(0))
     }
 
     @Test
@@ -168,15 +168,15 @@
         onPanelExpansionChanged_apliesBlur_ifShade()
         clearInvocations(shadeAnimation)
         notificationShadeDepthController.onPanelExpansionChanged(event)
-        verify(shadeAnimation, never()).animateTo(anyInt(), any())
+        verify(shadeAnimation, never()).animateTo(anyInt())
 
         notificationShadeDepthController.onPanelExpansionChanged(
             event.copy(fraction = 0.9f, tracking = true))
-        verify(shadeAnimation, never()).animateTo(anyInt(), any())
+        verify(shadeAnimation, never()).animateTo(anyInt())
 
         notificationShadeDepthController.onPanelExpansionChanged(
             event.copy(fraction = 0.8f, tracking = false))
-        verify(shadeAnimation).animateTo(eq(0), any())
+        verify(shadeAnimation).animateTo(eq(0))
     }
 
     @Test
@@ -186,7 +186,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 0.6f, expanded = true, tracking = true, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(maxBlur), any())
+        verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
     @Test
@@ -212,7 +212,7 @@
 
         statusBarState = StatusBarState.KEYGUARD
         statusBarStateListener.onStateChanged(statusBarState)
-        verify(shadeAnimation).animateTo(eq(0), any())
+        verify(shadeAnimation).animateTo(eq(0))
     }
 
     @Test
@@ -395,13 +395,13 @@
     @Test
     fun brightnessMirrorVisible_whenVisible() {
         notificationShadeDepthController.brightnessMirrorVisible = true
-        verify(brightnessSpring).animateTo(eq(maxBlur), any())
+        verify(brightnessSpring).animateTo(eq(maxBlur))
     }
 
     @Test
     fun brightnessMirrorVisible_whenHidden() {
         notificationShadeDepthController.brightnessMirrorVisible = false
-        verify(brightnessSpring).animateTo(eq(0), any())
+        verify(brightnessSpring).animateTo(eq(0))
     }
 
     @Test
@@ -424,7 +424,7 @@
     fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
         `when`(shadeAnimation.radius).thenReturn(0f)
         notificationShadeDepthController.blursDisabledForAppLaunch = true
-        verify(shadeAnimation, never()).animateTo(anyInt(), any())
+        verify(shadeAnimation, never()).animateTo(anyInt())
     }
 
     private fun enableSplitShade() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
new file mode 100644
index 0000000..44cbe51
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.atLeast
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class PulseExpansionHandlerTest : SysuiTestCase() {
+
+    private lateinit var pulseExpansionHandler: PulseExpansionHandler
+
+    private val collapsedHeight = 300
+    private val wakeUpCoordinator: NotificationWakeUpCoordinator = mock()
+    private val bypassController: KeyguardBypassController = mock()
+    private val headsUpManager: HeadsUpManagerPhone = mock()
+    private val roundnessManager: NotificationRoundnessManager = mock()
+    private val configurationController: ConfigurationController = mock()
+    private val statusBarStateController: StatusBarStateController = mock()
+    private val falsingManager: FalsingManager = mock()
+    private val lockscreenShadeTransitionController: LockscreenShadeTransitionController = mock()
+    private val falsingCollector: FalsingCollector = mock()
+    private val dumpManager: DumpManager = mock()
+    private val expandableView: ExpandableView = mock()
+
+    @Before
+    fun setUp() {
+        whenever(expandableView.collapsedHeight).thenReturn(collapsedHeight)
+
+        pulseExpansionHandler = PulseExpansionHandler(
+                mContext,
+                wakeUpCoordinator,
+                bypassController,
+                headsUpManager,
+                roundnessManager,
+                configurationController,
+                statusBarStateController,
+                falsingManager,
+                lockscreenShadeTransitionController,
+                falsingCollector,
+                dumpManager
+        )
+    }
+
+    @Test
+    fun resetChild_updateHeight() {
+        whenever(expandableView.actualHeight).thenReturn(500)
+
+        pulseExpansionHandler.reset(expandableView, animationDuration = 0)
+
+        verify(expandableView, atLeast(1)).actualHeight = collapsedHeight
+    }
+
+    @Test
+    fun resetChild_dontUpdateHeight() {
+        whenever(expandableView.actualHeight).thenReturn(collapsedHeight)
+
+        pulseExpansionHandler.reset(expandableView, animationDuration = 0)
+
+        verify(expandableView, never()).actualHeight = anyInt()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
new file mode 100644
index 0000000..11798a7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.stack
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val MAX_PULSE_HEIGHT = 100000f
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AmbientStateTest : SysuiTestCase() {
+
+    private val dumpManager = mock<DumpManager>()
+    private val sectionProvider = StackScrollAlgorithm.SectionProvider { _, _ -> false }
+    private val bypassController = StackScrollAlgorithm.BypassController { false }
+    private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
+
+    private lateinit var sut: AmbientState
+
+    @Before
+    fun setUp() {
+        sut =
+            AmbientState(
+                context,
+                dumpManager,
+                sectionProvider,
+                bypassController,
+                statusBarKeyguardViewManager,
+            )
+    }
+
+    // region isDimmed
+    @Test
+    fun isDimmed_whenTrue_shouldReturnTrue() {
+        sut.arrangeDimmed(true)
+
+        assertThat(sut.isDimmed).isTrue()
+    }
+
+    @Test
+    fun isDimmed_whenFalse_shouldReturnFalse() {
+        sut.arrangeDimmed(false)
+
+        assertThat(sut.isDimmed).isFalse()
+    }
+
+    @Test
+    fun isDimmed_whenDozeAmountIsEmpty_shouldReturnTrue() {
+        sut.arrangeDimmed(true)
+        sut.dozeAmount = 0f
+
+        assertThat(sut.isDimmed).isTrue()
+    }
+
+    @Test
+    fun isDimmed_whenPulseExpandingIsFalse_shouldReturnTrue() {
+        sut.arrangeDimmed(true)
+        sut.arrangePulseExpanding(false)
+        sut.dozeAmount = 1f // arrangePulseExpanding changes dozeAmount
+
+        assertThat(sut.isDimmed).isTrue()
+    }
+    // endregion
+
+    // region pulseHeight
+    @Test
+    fun pulseHeight_whenValueChanged_shouldCallListener() {
+        var listenerCalledCount = 0
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+        sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
+
+        sut.pulseHeight = 0f
+
+        assertThat(listenerCalledCount).isEqualTo(1)
+    }
+
+    @Test
+    fun pulseHeight_whenSetSameValue_shouldDoNothing() {
+        var listenerCalledCount = 0
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+        sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
+
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+
+        assertThat(listenerCalledCount).isEqualTo(0)
+    }
+
+    @Test
+    fun pulseHeight_whenValueIsFull_shouldReturn0() {
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun pulseHeight_whenValueIsNotFull_shouldReturnValue() {
+        val expected = MAX_PULSE_HEIGHT - 0.1f
+        sut.pulseHeight = expected
+
+        assertThat(sut.pulseHeight).isEqualTo(expected)
+    }
+    // endregion
+
+    // region statusBarState
+    @Test
+    fun statusBarState_whenPreviousStateIsNotKeyguardAndChange_shouldSetIsFlingRequiredToFalse() {
+        sut.setStatusBarState(StatusBarState.SHADE)
+        sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+        sut.setStatusBarState(StatusBarState.KEYGUARD)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+    }
+
+    @Test
+    fun statusBarState_whenPreviousStateIsKeyguardAndChange_shouldDoNothing() {
+        sut.setStatusBarState(StatusBarState.KEYGUARD)
+        sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+        sut.setStatusBarState(StatusBarState.SHADE)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+    // endregion
+
+    // region hideAmount
+    @Test
+    fun hideAmount_whenSetToFullValue_shouldReturnZeroFromPulseHeight() {
+        sut.hideAmount = 0f
+        sut.pulseHeight = 1f
+
+        sut.hideAmount = 1f
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun hideAmount_whenSetToAnyNotFullValue_shouldDoNothing() {
+        sut.hideAmount = 1f
+        sut.pulseHeight = 1f
+
+        sut.hideAmount = 0f
+
+        assertThat(sut.pulseHeight).isEqualTo(1f)
+    }
+    // endregion
+
+    // region dozeAmount
+    @Test
+    fun dozeAmount_whenDozeAmountIsSetToFullDozing_shouldReturnZeroFromPulseHeight() {
+        sut.dozeAmount = 0f
+        sut.pulseHeight = 1f
+
+        sut.dozeAmount = 1f
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun dozeAmount_whenDozeAmountIsSetToFullAwake_shouldReturnZeroFromPulseHeight() {
+        sut.dozeAmount = 1f
+        sut.pulseHeight = 1f
+
+        sut.dozeAmount = 0f
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun dozeAmount_whenDozeAmountIsSetAnyValueNotFullAwakeOrDozing_shouldDoNothing() {
+        sut.dozeAmount = 1f
+        sut.pulseHeight = 1f
+
+        sut.dozeAmount = 0.5f
+
+        assertThat(sut.pulseHeight).isEqualTo(1f)
+    }
+    // endregion
+
+    // region trackedHeadsUpRow
+    @Test
+    fun trackedHeadsUpRow_whenIsAboveTheShelf_shouldReturnInstance() {
+        sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(true) }
+
+        assertThat(sut.trackedHeadsUpRow).isNotNull()
+    }
+
+    @Test
+    fun trackedHeadsUpRow_whenIsNotAboveTheShelf_shouldReturnNull() {
+        sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(false) }
+
+        assertThat(sut.trackedHeadsUpRow).isNull()
+    }
+    // endregion
+
+    // region isSwipingUp
+    @Test
+    fun isSwipingUp_whenValueChangedToTrue_shouldRequireFling() {
+        sut.isSwipingUp = false
+        sut.isFlingRequiredAfterLockScreenSwipeUp = false
+
+        sut.isSwipingUp = true
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+    }
+
+    @Test
+    fun isSwipingUp_whenValueChangedToFalse_shouldRequireFling() {
+        sut.isSwipingUp = true
+        sut.isFlingRequiredAfterLockScreenSwipeUp = false
+
+        sut.isSwipingUp = false
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+    // endregion
+
+    // region isFlinging
+    @Test
+    fun isFlinging_shouldNotNeedFling() {
+        sut.arrangeFlinging(true)
+
+        sut.setFlinging(false)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+    }
+
+    @Test
+    fun isFlinging_whenNotOnLockScreen_shouldDoNothing() {
+        sut.arrangeFlinging(true)
+        sut.setStatusBarState(StatusBarState.SHADE)
+        sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+        sut.setFlinging(false)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+
+    @Test
+    fun isFlinging_whenValueChangedToTrue_shouldDoNothing() {
+        sut.arrangeFlinging(false)
+
+        sut.setFlinging(true)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+    // endregion
+
+    // region scrollY
+    @Test
+    fun scrollY_shouldSetValueGreaterThanZero() {
+        sut.scrollY = 0
+
+        sut.scrollY = 1
+
+        assertThat(sut.scrollY).isEqualTo(1)
+    }
+
+    @Test
+    fun scrollY_shouldNotSetValueLessThanZero() {
+        sut.scrollY = 0
+
+        sut.scrollY = -1
+
+        assertThat(sut.scrollY).isEqualTo(0)
+    }
+    // endregion
+
+    // region setOverScrollAmount
+    fun setOverScrollAmount_shouldSetValueOnTop() {
+        sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ true)
+
+        val resultOnTop = sut.getOverScrollAmount(/* top = */ true)
+        val resultOnBottom = sut.getOverScrollAmount(/* top = */ false)
+
+        assertThat(resultOnTop).isEqualTo(10f)
+        assertThat(resultOnBottom).isEqualTo(0f)
+    }
+
+    fun setOverScrollAmount_shouldSetValueOnBottom() {
+        sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ false)
+
+        val resultOnTop = sut.getOverScrollAmount(/* top */ true)
+        val resultOnBottom = sut.getOverScrollAmount(/* top */ false)
+
+        assertThat(resultOnTop).isEqualTo(0f)
+        assertThat(resultOnBottom).isEqualTo(10f)
+    }
+    // endregion
+
+    // region IsPulseExpanding
+    @Test
+    fun isPulseExpanding_shouldReturnTrue() {
+        sut.arrangePulseExpanding(true)
+
+        assertThat(sut.isPulseExpanding).isTrue()
+    }
+
+    @Test
+    fun isPulseExpanding_whenPulseHeightIsMax_shouldReturnFalse() {
+        sut.arrangePulseExpanding(true)
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+
+        assertThat(sut.isPulseExpanding).isFalse()
+    }
+
+    @Test
+    fun isPulseExpanding_whenDozeAmountIsZero_shouldReturnFalse() {
+        sut.arrangePulseExpanding(true)
+        sut.dozeAmount = 0f
+
+        assertThat(sut.isPulseExpanding).isFalse()
+    }
+
+    @Test
+    fun isPulseExpanding_whenHideAmountIsFull_shouldReturnFalse() {
+        sut.arrangePulseExpanding(true)
+        sut.hideAmount = 1f
+
+        assertThat(sut.isPulseExpanding).isFalse()
+    }
+    // endregion
+
+    // region isOnKeyguard
+    @Test
+    fun isOnKeyguard_whenStatusBarStateIsKeyguard_shouldReturnTrue() {
+        sut.setStatusBarState(StatusBarState.KEYGUARD)
+
+        assertThat(sut.isOnKeyguard).isTrue()
+    }
+
+    @Test
+    fun isOnKeyguard_whenStatusBarStateIsNotKeyguard_shouldReturnFalse() {
+        sut.setStatusBarState(StatusBarState.SHADE)
+
+        assertThat(sut.isOnKeyguard).isFalse()
+    }
+    // endregion
+}
+
+// region Arrange helper methods.
+private fun AmbientState.arrangeDimmed(value: Boolean) {
+    isDimmed = value
+    dozeAmount = if (value) 0f else 1f
+    arrangePulseExpanding(!value)
+}
+
+private fun AmbientState.arrangePulseExpanding(value: Boolean) {
+    if (value) {
+        dozeAmount = 1f
+        hideAmount = 0f
+        pulseHeight = 0f
+    } else {
+        dozeAmount = 0f
+        hideAmount = 1f
+        pulseHeight = MAX_PULSE_HEIGHT
+    }
+}
+
+private fun AmbientState.arrangeFlinging(value: Boolean) {
+    setStatusBarState(StatusBarState.KEYGUARD)
+    setFlinging(value)
+    isFlingRequiredAfterLockScreenSwipeUp = true
+}
+// endregion
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 3f19036..7741813 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -3,15 +3,22 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
+import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.statusbar.NotificationShelf
 import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
-import junit.framework.Assert.*
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState
+import com.android.systemui.util.mockito.mock
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.*
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.`when` as whenever
 
 /**
@@ -22,13 +29,18 @@
 @RunWithLooper
 class NotificationShelfTest : SysuiTestCase() {
 
-    private val shelf = NotificationShelf(context, /* attrs */ null)
+    private val shelf = NotificationShelf(
+            context,
+            /* attrs */ null,
+            /* showNotificationShelf */true
+    )
     private val shelfState = shelf.viewState as NotificationShelf.ShelfState
     private val ambientState = mock(AmbientState::class.java)
+    private val hostLayoutController: NotificationStackScrollLayoutController = mock()
 
     @Before
     fun setUp() {
-        shelf.bind(ambientState, /* hostLayoutController */ null)
+        shelf.bind(ambientState, /* hostLayoutController */ hostLayoutController)
         shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5)
     }
 
@@ -37,7 +49,7 @@
         setFractionToShade(0f)
         setOnLockscreen(true)
 
-        shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f);
+        shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f)
         assertTrue(shelf.actualWidth == 10)
 
         shelf.updateActualWidth(/* fractionToShade */ 0.5f, /* shortestWidth */ 10f)
@@ -155,7 +167,7 @@
         whenever(expandableView.actualHeight).thenReturn(20)
 
         whenever(expandableView.minHeight).thenReturn(20)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(true)
 
         whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -182,7 +194,7 @@
         whenever(expandableView.actualHeight).thenReturn(20)
 
         whenever(expandableView.minHeight).thenReturn(20)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(true)
 
         whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -209,7 +221,7 @@
         whenever(expandableView.actualHeight).thenReturn(25)
 
         whenever(expandableView.minHeight).thenReturn(25)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(true)
 
         whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -236,7 +248,7 @@
         whenever(expandableView.actualHeight).thenReturn(10)
 
         whenever(expandableView.minHeight).thenReturn(10)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(false)
 
         whenever(ambientState.isExpansionChanging).thenReturn(false)
@@ -251,6 +263,42 @@
         assertEquals(0f, amountInShelf)
     }
 
+    @Test
+    fun updateState_expansionChanging_shelfTransparent() {
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.25f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    fun updateState_expansionChangingWhileBouncerInTransit_shelfTransparent() {
+        whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.85f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    fun updateState_expansionChanging_shelfAlphaUpdated() {
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.6f,
+                expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f)
+        )
+    }
+
+    @Test
+    fun updateState_expansionChangingWhileBouncerInTransit_shelfAlphaUpdated() {
+        whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.95f,
+                expectedAlpha = aboutToShowBouncerProgress(0.95f)
+        )
+    }
+
     private fun setFractionToShade(fraction: Float) {
         whenever(ambientState.fractionToShade).thenReturn(fraction)
     }
@@ -258,4 +306,19 @@
     private fun setOnLockscreen(isOnLockscreen: Boolean) {
         whenever(ambientState.isOnKeyguard).thenReturn(isOnLockscreen)
     }
-}
\ No newline at end of file
+
+    private fun updateState_expansionChanging_shelfAlphaUpdated(
+            expansionFraction: Float,
+            expectedAlpha: Float
+    ) {
+        whenever(ambientState.lastVisibleBackgroundChild)
+                .thenReturn(ExpandableNotificationRow(mContext, null))
+        whenever(ambientState.isExpansionChanging).thenReturn(true)
+        whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
+        whenever(hostLayoutController.speedBumpIndex).thenReturn(0)
+
+        shelf.updateState(StackScrollAlgorithmState(), ambientState)
+
+        assertEquals(expectedAlpha, shelf.viewState.alpha)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 3c22edc..6ae021b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -250,7 +250,7 @@
         // Validate that when the animation ends the stackEndHeight is recalculated immediately
         clearInvocations(mAmbientState);
         mStackScroller.setPanelFlinging(false);
-        verify(mAmbientState).setIsFlinging(eq(false));
+        verify(mAmbientState).setFlinging(eq(false));
         verify(mAmbientState).setStackEndHeight(anyFloat());
         verify(mAmbientState).setStackHeight(anyFloat());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 35d2363b..40aec82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -20,7 +20,10 @@
 import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
+import org.mockito.Mockito.any
+import org.mockito.Mockito.eq
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
@@ -35,7 +38,6 @@
     private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
         layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
     }
-
     private val ambientState = AmbientState(
             context,
             dumpManager,
@@ -115,29 +117,54 @@
     }
 
     @Test
-    fun resetViewStates_isExpansionChanging_viewBecomesTransparent() {
+    fun resetViewStates_expansionChanging_notificationBecomesTransparent() {
         whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
-        ambientState.isExpansionChanging = true
-        ambientState.expansionFraction = 0.25f
-        stackScrollAlgorithm.initView(context)
-
-        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
-
-        val expected = getContentAlpha(0.25f)
-        assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.25f,
+                expectedAlpha = 0.0f
+        )
     }
 
     @Test
-    fun resetViewStates_isExpansionChangingWhileBouncerInTransit_viewBecomesTransparent() {
+    fun resetViewStates_expansionChangingWhileBouncerInTransit_viewBecomesTransparent() {
         whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.85f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    fun resetViewStates_expansionChanging_notificationAlphaUpdated() {
+        whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.6f,
+                expectedAlpha = getContentAlpha(0.6f)
+        )
+    }
+
+    @Test
+    fun resetViewStates_expansionChangingWhileBouncerInTransit_notificationAlphaUpdated() {
+        whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.95f,
+                expectedAlpha = aboutToShowBouncerProgress(0.95f)
+        )
+    }
+
+    @Test
+    fun resetViewStates_expansionChanging_shelfUpdated() {
+        ambientState.shelf = notificationShelf
         ambientState.isExpansionChanging = true
-        ambientState.expansionFraction = 0.25f
+        ambientState.expansionFraction = 0.6f
         stackScrollAlgorithm.initView(context)
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
 
-        val expected = aboutToShowBouncerProgress(0.25f)
-        assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+        verify(notificationShelf).updateState(
+                /* algorithmState= */any(),
+                /* ambientState= */eq(ambientState)
+        )
     }
 
     @Test
@@ -179,7 +206,28 @@
     }
 
     @Test
-    fun resetViewStates_hiddenShelf_viewAlphaDoesNotChange() {
+    fun resetViewStates_hiddenShelf_allRowsBecomesTransparent() {
+        hostView.removeAllViews()
+        val row1 = mockExpandableNotificationRow()
+        hostView.addView(row1)
+        val row2 = mockExpandableNotificationRow()
+        hostView.addView(row2)
+
+        ambientState.setStatusBarState(StatusBarState.KEYGUARD)
+        ambientState.hideAmount = 0.25f
+        notificationShelf.viewState.hidden = true
+        ambientState.shelf = notificationShelf
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        val expected = 1f - ambientState.hideAmount
+        assertThat(row1.viewState.alpha).isEqualTo(expected)
+        assertThat(row2.viewState.alpha).isEqualTo(expected)
+    }
+
+    @Test
+    fun resetViewStates_hiddenShelf_shelfAlphaDoesNotChange() {
         val expected = notificationShelf.viewState.alpha
         notificationShelf.viewState.hidden = true
         ambientState.shelf = notificationShelf
@@ -458,4 +506,23 @@
                 /* originalCornerRoundness= */ 1f)
         assertEquals(1f, currentRoundness)
     }
+
+    private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
+            expansionFraction: Float,
+            expectedAlpha: Float
+    ) {
+        ambientState.isExpansionChanging = true
+        ambientState.expansionFraction = expansionFraction
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationRow.viewState.alpha).isEqualTo(expectedAlpha)
+    }
+}
+
+private fun mockExpandableNotificationRow(): ExpandableNotificationRow {
+    return mock(ExpandableNotificationRow::class.java).apply {
+        whenever(viewState).thenReturn(ExpandableViewState())
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index cce2e89..365e608 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -20,7 +20,6 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -45,13 +44,11 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.VibratorHelper;
@@ -90,8 +87,6 @@
     @Mock
     private BiometricUnlockController.BiometricModeListener mBiometricModeListener;
     @Mock
-    private ShadeController mShadeController;
-    @Mock
     private KeyguardStateController mKeyguardStateController;
     @Mock
     private Handler mHandler;
@@ -112,8 +107,6 @@
     @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
-    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
-    @Mock
     private SessionTracker mSessionTracker;
     @Mock
     private LatencyTracker mLatencyTracker;
@@ -137,12 +130,12 @@
         when(mVibratorHelper.hasVibrator()).thenReturn(true);
         mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
         mBiometricUnlockController = new BiometricUnlockController(mDozeScrimController,
-                mKeyguardViewMediator, mScrimController, mShadeController,
+                mKeyguardViewMediator, mScrimController,
                 mNotificationShadeWindowController, mKeyguardStateController, mHandler,
                 mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters,
                 mMetricsLogger, mDumpManager, mPowerManager,
                 mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
-                mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController,
+                mAuthController, mStatusBarStateController,
                 mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper);
         mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener);
@@ -167,8 +160,6 @@
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FINGERPRINT, false /* isStrongBiometric */);
         verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean());
-        verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(),
-                anyFloat());
         assertThat(mBiometricUnlockController.getMode())
                 .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
         assertThat(mBiometricUnlockController.getBiometricType())
@@ -246,8 +237,6 @@
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FACE, true /* isStrongBiometric */);
 
-        verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
-                anyBoolean(), anyFloat());
         verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
         assertThat(mBiometricUnlockController.getMode())
                 .isEqualTo(BiometricUnlockController.MODE_NONE);
@@ -298,10 +287,6 @@
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FACE, true /* isStrongBiometric */);
 
-        // Wake up before showing the bouncer
-        verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
-        mBiometricUnlockController.mWakefulnessObserver.onFinishedWakingUp();
-
         verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean());
         assertThat(mBiometricUnlockController.getMode())
                 .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
@@ -332,8 +317,6 @@
                 BiometricSourceType.FACE, true /* isStrongBiometric */);
 
         verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
-        verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
-                anyBoolean(), anyFloat());
         assertThat(mBiometricUnlockController.getMode())
                 .isEqualTo(BiometricUnlockController.MODE_NONE);
     }
@@ -383,8 +366,6 @@
         mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
                 BiometricSourceType.FACE, true /* isStrongBiometric */);
 
-        verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(),
-                anyBoolean(), anyFloat());
         assertThat(mBiometricUnlockController.getMode())
                 .isEqualTo(BiometricUnlockController.MODE_ONLY_WAKE);
     }
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 14b7471..f510e48 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
@@ -35,6 +35,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -69,7 +70,11 @@
 import android.util.SparseArray;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import androidx.test.filters.SmallTest;
 
@@ -168,6 +173,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -279,6 +285,15 @@
     @Mock private InteractionJankMonitor mJankMonitor;
     @Mock private DeviceStateManager mDeviceStateManager;
     @Mock private WiredChargingRippleController mWiredChargingRippleController;
+    /**
+     * The process of registering/unregistering a predictive back callback requires a
+     * ViewRootImpl, which is present IRL, but may be missing during a Mockito unit test.
+     * To prevent an NPE during test execution, we explicitly craft and provide a fake ViewRootImpl.
+     */
+    @Mock private ViewRootImpl mViewRootImpl;
+    @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
+    @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
+
     private ShadeController mShadeController;
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
     private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -368,10 +383,10 @@
             return null;
         }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
 
-        mShadeController = new ShadeControllerImpl(mCommandQueue,
+        mShadeController = spy(new ShadeControllerImpl(mCommandQueue,
                 mStatusBarStateController, mNotificationShadeWindowController,
                 mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
-                () -> Optional.of(mCentralSurfaces), () -> mAssistManager);
+                () -> Optional.of(mCentralSurfaces), () -> mAssistManager));
 
         when(mOperatorNameViewControllerFactory.create(any()))
                 .thenReturn(mOperatorNameViewController);
@@ -460,7 +475,14 @@
                 mActivityLaunchAnimator,
                 mJankMonitor,
                 mDeviceStateManager,
-                mWiredChargingRippleController, mDreamManager);
+                mWiredChargingRippleController, mDreamManager) {
+            @Override
+            protected ViewRootImpl getViewRootImpl() {
+                return mViewRootImpl;
+            }
+        };
+        when(mViewRootImpl.getOnBackInvokedDispatcher())
+                .thenReturn(mOnBackInvokedDispatcher);
         when(mKeyguardViewMediator.registerCentralSurfaces(
                 any(CentralSurfacesImpl.class),
                 any(NotificationPanelViewController.class),
@@ -738,6 +760,43 @@
         }
     }
 
+    /**
+     * Do the following:
+     * 1. verify that a predictive back callback is registered when CSurf becomes visible
+     * 2. verify that the same callback is unregistered when CSurf becomes invisible
+     */
+    @Test
+    public void testPredictiveBackCallback_registration() {
+        mCentralSurfaces.handleVisibleToUserChanged(true);
+        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
+                mOnBackInvokedCallback.capture());
+
+        mCentralSurfaces.handleVisibleToUserChanged(false);
+        verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
+                eq(mOnBackInvokedCallback.getValue()));
+    }
+
+    /**
+     * Do the following:
+     * 1. capture the predictive back callback during registration
+     * 2. call the callback directly
+     * 3. verify that the ShadeController's panel collapse animation is invoked
+     */
+    @Test
+    public void testPredictiveBackCallback_invocationCollapsesPanel() {
+        mCentralSurfaces.setNotificationShadeWindowViewController(
+                mNotificationShadeWindowViewController);
+        mCentralSurfaces.handleVisibleToUserChanged(true);
+        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
+                mOnBackInvokedCallback.capture());
+
+        when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true);
+        mOnBackInvokedCallback.getValue().onBackInvoked();
+        verify(mShadeController).animateCollapsePanels();
+    }
+
     @Test
     public void testPanelOpenForHeadsUp() {
         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 5c9871a..9de9db1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -29,6 +29,7 @@
 
 import android.os.PowerManager;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 
 import androidx.test.filters.SmallTest;
@@ -61,10 +62,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Optional;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
 public class DozeServiceHostTest extends SysuiTestCase {
 
     private DozeServiceHost mDozeServiceHost;
@@ -92,6 +93,7 @@
     @Mock private View mAmbientIndicationContainer;
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private AuthController mAuthController;
+    @Mock private DozeHost.Callback mCallback;
 
     @Before
     public void setup() {
@@ -100,7 +102,7 @@
                 mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
                 mBatteryController, mScrimController, () -> mBiometricUnlockController,
                 mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
-                mKeyguardUpdateMonitor, mPulseExpansionHandler, Optional.empty(),
+                mKeyguardUpdateMonitor, mPulseExpansionHandler,
                 mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
                 mAuthController, mNotificationIconAreaController);
 
@@ -114,16 +116,19 @@
 
     @Test
     public void testStartStopDozing() {
+        mDozeServiceHost.addCallback(mCallback);
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
         when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
 
         assertFalse(mDozeServiceHost.getDozingRequested());
 
         mDozeServiceHost.startDozing();
+        verify(mCallback).onDozingChanged(eq(true));
         verify(mStatusBarStateController).setIsDozing(eq(true));
         verify(mCentralSurfaces).updateIsKeyguard();
 
         mDozeServiceHost.stopDozing();
+        verify(mCallback).onDozingChanged(eq(false));
         verify(mStatusBarStateController).setIsDozing(eq(false));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
deleted file mode 100644
index 3440fa5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.android.systemui.statusbar.phone
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.assist.AssistManager
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.policy.AccessibilityController
-import com.android.systemui.statusbar.policy.FlashlightController
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.tuner.TunerService
-import java.util.concurrent.Executor
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class KeyguardBottomAreaTest : SysuiTestCase() {
-
-    @Mock
-    private lateinit var mCentralSurfaces: CentralSurfaces
-    private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
-
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-        // Mocked dependencies
-        mDependency.injectMockDependency(AccessibilityController::class.java)
-        mDependency.injectMockDependency(ActivityStarter::class.java)
-        mDependency.injectMockDependency(AssistManager::class.java)
-        mDependency.injectTestDependency(Executor::class.java, Executor { it.run() })
-        mDependency.injectMockDependency(FlashlightController::class.java)
-        mDependency.injectMockDependency(KeyguardStateController::class.java)
-        mDependency.injectMockDependency(TunerService::class.java)
-
-        mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
-                R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
-    }
-
-    @Test
-    fun initFrom_doesntCrash() {
-        val other = LayoutInflater.from(mContext).inflate(R.layout.keyguard_bottom_area,
-                null, false) as KeyguardBottomAreaView
-
-        other.initFrom(mKeyguardBottomArea)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 60a3d95..ab209d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -408,6 +408,16 @@
         mBouncer.hide(false /* destroyView */);
         verify(mHandler).removeCallbacks(eq(showRunnable.getValue()));
     }
+
+    @Test
+    public void testShow_doesNotDelaysIfFaceAuthIsLockedOut() {
+        when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(true);
+        mBouncer.show(true /* reset */);
+
+        verify(mHandler, never()).postDelayed(any(), anyLong());
+    }
+
     @Test
     public void testShow_delaysIfFaceAuthIsRunning_unlessBypassEnabled() {
         when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7cd275d..4d1a52c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -59,16 +59,19 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.scrim.ScrimView;
-import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.FakeConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
 import com.android.systemui.utils.os.FakeHandler;
 
+import com.google.common.truth.Expect;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -86,6 +89,11 @@
 @SmallTest
 public class ScrimControllerTest extends SysuiTestCase {
 
+    @Rule public Expect mExpect = Expect.create();
+
+    private final FakeConfigurationController mConfigurationController =
+            new FakeConfigurationController();
+
     private ScrimController mScrimController;
     private ScrimView mScrimBehind;
     private ScrimView mNotificationsScrim;
@@ -96,32 +104,19 @@
     private int mScrimVisibility;
     private boolean mAlwaysOnEnabled;
     private TestableLooper mLooper;
-    @Mock
-    private AlarmManager mAlarmManager;
-    @Mock
-    private DozeParameters mDozeParameters;
-    @Mock
-    LightBarController mLightBarController;
-    @Mock
-    DelayedWakeLock.Builder mDelayedWakeLockBuilder;
-    @Mock
-    private DelayedWakeLock mWakeLock;
-    @Mock
-    KeyguardStateController mKeyguardStateController;
-    @Mock
-    KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock
-    private DockManager mDockManager;
-    @Mock
-    private ConfigurationController mConfigurationController;
-    @Mock
-    private ScreenOffAnimationController mScreenOffAnimationController;
-    @Mock
-    private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+    @Mock private AlarmManager mAlarmManager;
+    @Mock private DozeParameters mDozeParameters;
+    @Mock private LightBarController mLightBarController;
+    @Mock private DelayedWakeLock.Builder mDelayedWakeLockBuilder;
+    @Mock private DelayedWakeLock mWakeLock;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private DockManager mDockManager;
+    @Mock private ScreenOffAnimationController mScreenOffAnimationController;
+    @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
     //   event-dispatch-on-registration pattern caused some of these unit tests to fail.)
-    @Mock
-    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     private static class AnimatorListener implements Animator.AnimatorListener {
         private int mNumStarts;
@@ -1450,6 +1445,41 @@
     }
 
     @Test
+    public void notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress() {
+        mScrimController.setClipsQsScrim(false);
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        // RawPanelExpansion and QsExpansion are usually used for the notification alpha
+        // calculation.
+        // Here we set them to non-zero values explicitly to make sure that in not clipped mode,
+        // they are not being used even when set.
+        mScrimController.setRawPanelExpansionFraction(0.5f);
+        mScrimController.setQsPosition(/* expansionFraction= */ 0.5f, /* qsPanelBottomY= */ 500);
+        finishAnimationsImmediately();
+
+        float progress = 0.5f;
+
+        float notificationExpansionProgress = 0f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 0.25f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 0.5f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 0.75f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+
+        notificationExpansionProgress = 1f;
+        mScrimController.setTransitionToFullShadeProgress(progress, notificationExpansionProgress);
+        mExpect.that(mNotificationsScrim.getViewAlpha()).isEqualTo(notificationExpansionProgress);
+    }
+
+    @Test
     public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() {
         int overScrollAmount = 10;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 2dcdcfc..e790d85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -51,6 +51,7 @@
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -277,6 +278,17 @@
     }
 
     @Test
+    public void onPanelExpansionChanged_neverTranslatesBouncerWhenShadeLocked() {
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+                expansionEvent(
+                        /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+                        /* expanded= */ true,
+                        /* tracking= */ false));
+        verify(mBouncer, never()).setExpansion(anyFloat());
+    }
+
+    @Test
     public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
         mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
         verify(mCentralSurfaces).animateKeyguardUnoccluding();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
new file mode 100644
index 0000000..6dbee2f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.HIDDEN_ICONS_TUNABLE_KEY
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class ConnectivityRepositoryImplTest : SysuiTestCase() {
+
+    private lateinit var underTest: ConnectivityRepositoryImpl
+
+    @Mock private lateinit var connectivitySlots: ConnectivitySlots
+    @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var logger: ConnectivityPipelineLogger
+    private lateinit var scope: CoroutineScope
+    @Mock private lateinit var tunerService: TunerService
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        scope = CoroutineScope(IMMEDIATE)
+
+        underTest = ConnectivityRepositoryImpl(
+            connectivitySlots,
+            context,
+            dumpManager,
+            logger,
+            scope,
+            tunerService,
+        )
+    }
+
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
+        setUpEthernetWifiMobileSlotNames()
+        context.getOrCreateTestableResources().addOverride(
+            DEFAULT_HIDDEN_ICONS_RESOURCE,
+            arrayOf(SLOT_WIFI, SLOT_ETHERNET)
+        )
+        // Re-create our [ConnectivityRepositoryImpl], since it fetches
+        // config_statusBarIconsToExclude when it's first constructed
+        underTest = ConnectivityRepositoryImpl(
+            connectivitySlots,
+            context,
+            dumpManager,
+            logger,
+            scope,
+            tunerService,
+        )
+
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_slotNamesAdded_flowHasSlots() = runBlocking(IMMEDIATE) {
+        setUpEthernetWifiMobileSlotNames()
+
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+
+        assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_wrongKey_doesNotUpdate() = runBlocking(IMMEDIATE) {
+        setUpEthernetWifiMobileSlotNames()
+
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+
+        // WHEN onTuningChanged with the wrong key
+        getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
+        yield()
+
+        // THEN we didn't update our value and still have the old one
+        assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_slotNamesAddedThenNull_flowHasDefault() = runBlocking(IMMEDIATE) {
+        setUpEthernetWifiMobileSlotNames()
+        context.getOrCreateTestableResources().addOverride(
+            DEFAULT_HIDDEN_ICONS_RESOURCE,
+            arrayOf(SLOT_WIFI, SLOT_ETHERNET)
+        )
+        // Re-create our [ConnectivityRepositoryImpl], since it fetches
+        // config_statusBarIconsToExclude when it's first constructed
+        underTest = ConnectivityRepositoryImpl(
+            connectivitySlots,
+            context,
+            dumpManager,
+            logger,
+            scope,
+            tunerService,
+        )
+
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        // First, update the slots
+        getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
+        assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
+
+        // WHEN we update to a null value
+        getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
+        yield()
+
+        // THEN we go back to our default value
+        assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
+            .thenReturn(ConnectivitySlot.WIFI)
+        whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+
+        getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
+
+        assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_someEmptySlotNames_flowHasValidSlotsOnly() = runBlocking(IMMEDIATE) {
+        setUpEthernetWifiMobileSlotNames()
+
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        // WHEN there's empty and blank slot names
+        getTunable().onTuningChanged(
+            HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE,  ,,$SLOT_WIFI"
+        )
+
+        // THEN we skip that slot but still process the other ones
+        assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() = runBlocking(IMMEDIATE) {
+        var latest: Set<ConnectivitySlot>? = null
+        val job = underTest
+            .forceHiddenSlots
+            .onEach { latest = it }
+            .launchIn(this)
+
+        whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
+        whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
+        whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
+
+        getTunable().onTuningChanged(
+            HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE,,$SLOT_WIFI,$SLOT_ETHERNET,,,"
+        )
+
+        assertThat(latest).isEmpty()
+
+        job.cancel()
+    }
+
+    @Test
+    fun forceHiddenSlots_newSubscriberGetsCurrentValue() = runBlocking(IMMEDIATE) {
+        setUpEthernetWifiMobileSlotNames()
+
+        var latest1: Set<ConnectivitySlot>? = null
+        val job1 = underTest
+            .forceHiddenSlots
+            .onEach { latest1 = it }
+            .launchIn(this)
+
+        getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
+
+        assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+
+        // WHEN we add a second subscriber after having already emitted a value
+        var latest2: Set<ConnectivitySlot>? = null
+        val job2 = underTest
+            .forceHiddenSlots
+            .onEach { latest2 = it }
+            .launchIn(this)
+
+        // THEN the second subscribe receives the already-emitted value
+        assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
+
+        job1.cancel()
+        job2.cancel()
+    }
+
+    private fun getTunable(): TunerService.Tunable {
+        val callbackCaptor = argumentCaptor<TunerService.Tunable>()
+        Mockito.verify(tunerService).addTunable(callbackCaptor.capture(), any())
+        return callbackCaptor.value!!
+    }
+
+    private fun setUpEthernetWifiMobileSlotNames() {
+        whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET))
+            .thenReturn(ConnectivitySlot.ETHERNET)
+        whenever(connectivitySlots.getSlotFromName(SLOT_WIFI))
+            .thenReturn(ConnectivitySlot.WIFI)
+        whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE))
+            .thenReturn(ConnectivitySlot.MOBILE)
+    }
+
+    companion object {
+        private const val SLOT_ETHERNET = "ethernet"
+        private const val SLOT_WIFI = "wifi"
+        private const val SLOT_MOBILE = "mobile"
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
new file mode 100644
index 0000000..bd70034
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.data.repository
+
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Fake implementation of [ConnectivityRepository] exposing set methods for all the flows. */
+class FakeConnectivityRepository : ConnectivityRepository {
+    private val _forceHiddenIcons: MutableStateFlow<Set<ConnectivitySlot>> =
+        MutableStateFlow(emptySet())
+    override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = _forceHiddenIcons
+
+    fun setForceHiddenIcons(hiddenIcons: Set<ConnectivitySlot>) {
+        _forceHiddenIcons.value = hiddenIcons
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
index 9d8b4bc..e896749 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
@@ -18,6 +18,8 @@
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
@@ -37,18 +39,22 @@
 
     private lateinit var underTest: WifiInteractor
 
-    private lateinit var repository: FakeWifiRepository
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
 
     @Before
     fun setUp() {
-        repository = FakeWifiRepository()
-        underTest = WifiInteractor(repository)
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        underTest = WifiInteractor(connectivityRepository, wifiRepository)
     }
 
     @Test
     fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
+        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -63,8 +69,10 @@
 
     @Test
     fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
+        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -79,8 +87,10 @@
 
     @Test
     fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -95,8 +105,10 @@
 
     @Test
     fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -111,8 +123,10 @@
 
     @Test
     fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -127,8 +141,10 @@
 
     @Test
     fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(WifiNetworkModel.Inactive)
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -143,8 +159,10 @@
 
     @Test
     fun hasActivityIn_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+        wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        )
 
         var latest: Boolean? = null
         val job = underTest
@@ -159,7 +177,7 @@
 
     @Test
     fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
 
         var latest: Boolean? = null
         val job = underTest
@@ -168,23 +186,33 @@
                 .launchIn(this)
 
         // Conduct a series of changes and verify we catch each of them in succession
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        )
         yield()
         assertThat(latest).isTrue()
 
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = true))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        )
         yield()
         assertThat(latest).isFalse()
 
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = true))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        )
         yield()
         assertThat(latest).isTrue()
 
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        )
         yield()
         assertThat(latest).isTrue()
 
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = false, hasActivityOut = false))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        )
         yield()
         assertThat(latest).isFalse()
 
@@ -200,7 +228,7 @@
             ssid = "AB",
             passpointProviderFriendlyName = "friendly"
         )
-        repository.setWifiNetwork(wifiNetwork)
+        wifiRepository.setWifiNetwork(wifiNetwork)
 
         var latest: WifiNetworkModel? = null
         val job = underTest
@@ -213,6 +241,36 @@
         job.cancel()
     }
 
+    @Test
+    fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
+        connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+
+        var latest: Boolean? = null
+        val job = underTest
+            .isForceHidden
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = runBlocking(IMMEDIATE) {
+        connectivityRepository.setForceHiddenIcons(setOf())
+
+        var latest: Boolean? = null
+        val job = underTest
+            .isForceHidden
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
     companion object {
         val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index f0a775b..43103a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -17,17 +17,24 @@
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
 import androidx.test.filters.SmallTest
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,60 +57,34 @@
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var logger: ConnectivityPipelineLogger
     @Mock private lateinit var constants: WifiConstants
-    private lateinit var repository: FakeWifiRepository
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
     private lateinit var interactor: WifiInteractor
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        repository = FakeWifiRepository()
-        interactor = WifiInteractor(repository)
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        interactor = WifiInteractor(connectivityRepository, wifiRepository)
 
         underTest = WifiViewModel(
             statusBarPipelineFlags,
             constants,
+            context,
             logger,
             interactor
         )
     }
 
     @Test
-    fun wifiIconResId_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(WifiNetworkModel.Inactive)
+    fun wifiIcon_forceHidden_outputsNull() = runBlocking(IMMEDIATE) {
+        connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
 
-        var latest: Int? = null
+        var latest: Icon? = null
         val job = underTest
-                .wifiIconResId
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isEqualTo(WIFI_NO_NETWORK)
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIconResId_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-
-        var latest: Int? = null
-        val job = underTest
-                .wifiIconResId
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIconResId_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
-        repository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
-
-        var latest: Int? = null
-        val job = underTest
-            .wifiIconResId
+            .wifiIcon
             .onEach { latest = it }
             .launchIn(this)
 
@@ -113,10 +94,77 @@
     }
 
     @Test
-    fun wifiIconResId_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
+    fun wifiIcon_notForceHidden_outputsVisible() = runBlocking(IMMEDIATE) {
+        connectivityRepository.setForceHiddenIcons(setOf())
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
+
+        var latest: Icon? = null
+        val job = underTest
+            .wifiIcon
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+
+        job.cancel()
+    }
+
+    @Test
+    fun wifiIcon_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+
+        var latest: Icon? = null
+        val job = underTest
+                .wifiIcon
+                .onEach { latest = it }
+                .launchIn(this)
+
+        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+        val icon = latest as Icon.Resource
+        assertThat(icon.res).isEqualTo(WIFI_NO_NETWORK)
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(WIFI_NO_CONNECTION))
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(NO_INTERNET))
+
+        job.cancel()
+    }
+
+    @Test
+    fun wifiIcon_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
+
+        var latest: Icon? = null
+        val job = underTest
+            .wifiIcon
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun wifiIcon_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
+
+        var latest: Icon? = null
+        val job = underTest
+            .wifiIcon
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun wifiIcon_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
         val level = 1
 
-        repository.setWifiNetwork(
+        wifiRepository.setWifiNetwork(
                 WifiNetworkModel.Active(
                         NETWORK_ID,
                         isValidated = true,
@@ -124,22 +172,28 @@
                 )
         )
 
-        var latest: Int? = null
+        var latest: Icon? = null
         val job = underTest
-                .wifiIconResId
-                .onEach { latest = it }
-                .launchIn(this)
+            .wifiIcon
+            .onEach { latest = it }
+            .launchIn(this)
 
-        assertThat(latest).isEqualTo(WIFI_FULL_ICONS[level])
+        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+        val icon = latest as Icon.Resource
+        assertThat(icon.res).isEqualTo(WIFI_FULL_ICONS[level])
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
+        assertThat(icon.contentDescription?.getAsString())
+            .doesNotContain(context.getString(NO_INTERNET))
 
         job.cancel()
     }
 
     @Test
-    fun wifiIconResId_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
+    fun wifiIcon_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
         val level = 4
 
-        repository.setWifiNetwork(
+        wifiRepository.setWifiNetwork(
                 WifiNetworkModel.Active(
                         NETWORK_ID,
                         isValidated = false,
@@ -147,13 +201,19 @@
                 )
         )
 
-        var latest: Int? = null
+        var latest: Icon? = null
         val job = underTest
-                .wifiIconResId
-                .onEach { latest = it }
-                .launchIn(this)
+            .wifiIcon
+            .onEach { latest = it }
+            .launchIn(this)
 
-        assertThat(latest).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
+        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
+        val icon = latest as Icon.Resource
+        assertThat(icon.res).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(NO_INTERNET))
 
         job.cancel()
     }
@@ -161,7 +221,7 @@
     @Test
     fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
         whenever(constants.shouldShowActivityConfig).thenReturn(false)
-        repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
 
         var latest: Boolean? = null
         val job = underTest
@@ -178,7 +238,7 @@
     @Test
     fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
         whenever(constants.shouldShowActivityConfig).thenReturn(false)
-        repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
 
         var latest: Boolean? = null
         val job = underTest
@@ -187,7 +247,9 @@
                 .launchIn(this)
 
         // Update the repo to have activityIn
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        )
         yield()
 
         // Verify that we didn't update to activityIn=true (because our config is false)
@@ -199,7 +261,7 @@
     @Test
     fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
         whenever(constants.shouldShowActivityConfig).thenReturn(true)
-        repository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
 
         var latest: Boolean? = null
         val job = underTest
@@ -208,7 +270,9 @@
                 .launchIn(this)
 
         // Update the repo to have activityIn
-        repository.setWifiActivity(WifiActivityModel(hasActivityIn = true, hasActivityOut = false))
+        wifiRepository.setWifiActivity(
+            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        )
         yield()
 
         // Verify that we updated to activityIn=true
@@ -217,6 +281,13 @@
         job.cancel()
     }
 
+    private fun ContentDescription.getAsString(): String? {
+        return when (this) {
+            is ContentDescription.Loaded -> this.description
+            is ContentDescription.Resource -> context.getString(this.res)
+        }
+    }
+
     companion object {
         private const val NETWORK_ID = 2
         private val ACTIVE_VALID_WIFI_NETWORK = WifiNetworkModel.Active(NETWORK_ID, ssid = "AB")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 4a8170f..8f363ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -31,6 +31,7 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
@@ -57,6 +58,8 @@
     private DumpManager mDumpManager;
     @Mock
     private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+    @Mock
+    private KeyguardUpdateMonitorLogger mLogger;
 
     @Before
     public void setup() {
@@ -66,6 +69,7 @@
                 mKeyguardUpdateMonitor,
                 mLockPatternUtils,
                 mKeyguardUnlockAnimationControllerLazy,
+                mLogger,
                 mDumpManager);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index c3805ad..8290dab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -57,8 +57,6 @@
     @Mock
     private lateinit var inflatedUserDetailItemView: KeyguardUserDetailItemView
     @Mock
-    private lateinit var userInfo: UserInfo
-    @Mock
     private lateinit var layoutInflater: LayoutInflater
     @Mock
     private lateinit var keyguardUserSwitcherController: KeyguardUserSwitcherController
@@ -188,7 +186,7 @@
 
     private fun createUserRecord(isCurrentUser: Boolean, isGuestUser: Boolean) =
         UserRecord(
-            userInfo,
+            UserInfo(0 /* id */, "name", 0 /* flags */),
             picture,
             isGuestUser,
             isCurrentUser,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
new file mode 100644
index 0000000..921b7ef
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import android.content.Context
+import android.os.PowerManager
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class TemporaryViewDisplayControllerTest : SysuiTestCase() {
+    private lateinit var underTest: TestController
+
+    private lateinit var fakeClock: FakeSystemClock
+    private lateinit var fakeExecutor: FakeExecutor
+
+    @Mock
+    private lateinit var logger: TemporaryViewLogger
+    @Mock
+    private lateinit var accessibilityManager: AccessibilityManager
+    @Mock
+    private lateinit var configurationController: ConfigurationController
+    @Mock
+    private lateinit var windowManager: WindowManager
+    @Mock
+    private lateinit var powerManager: PowerManager
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any()))
+            .thenReturn(TIMEOUT_MS.toInt())
+
+        fakeClock = FakeSystemClock()
+        fakeExecutor = FakeExecutor(fakeClock)
+
+        underTest = TestController(
+                context,
+                logger,
+                windowManager,
+                fakeExecutor,
+                accessibilityManager,
+                configurationController,
+                powerManager,
+        )
+    }
+
+    @Test
+    fun displayView_viewAdded() {
+        underTest.displayView(getState())
+
+        verify(windowManager).addView(any(), any())
+    }
+
+    @Test
+    fun displayView_screenOff_screenWakes() {
+        whenever(powerManager.isScreenOn).thenReturn(false)
+
+        underTest.displayView(getState())
+
+        verify(powerManager).wakeUp(any(), any(), any())
+    }
+
+    @Test
+    fun displayView_screenAlreadyOn_screenNotWoken() {
+        whenever(powerManager.isScreenOn).thenReturn(true)
+
+        underTest.displayView(getState())
+
+        verify(powerManager, never()).wakeUp(any(), any(), any())
+    }
+
+    @Test
+    fun displayView_twice_viewNotAddedTwice() {
+        underTest.displayView(getState())
+        reset(windowManager)
+
+        underTest.displayView(getState())
+        verify(windowManager, never()).addView(any(), any())
+    }
+
+    @Test
+    fun displayView_viewDoesNotDisappearsBeforeTimeout() {
+        val state = getState()
+        underTest.displayView(state)
+        reset(windowManager)
+
+        fakeClock.advanceTime(TIMEOUT_MS - 1)
+
+        verify(windowManager, never()).removeView(any())
+    }
+
+    @Test
+    fun displayView_viewDisappearsAfterTimeout() {
+        val state = getState()
+        underTest.displayView(state)
+        reset(windowManager)
+
+        fakeClock.advanceTime(TIMEOUT_MS + 1)
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun displayView_calledAgainBeforeTimeout_timeoutReset() {
+        // First, display the view
+        val state = getState()
+        underTest.displayView(state)
+
+        // After some time, re-display the view
+        val waitTime = 1000L
+        fakeClock.advanceTime(waitTime)
+        underTest.displayView(getState())
+
+        // Wait until the timeout for the first display would've happened
+        fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1)
+
+        // Verify we didn't hide the view
+        verify(windowManager, never()).removeView(any())
+    }
+
+    @Test
+    fun displayView_calledAgainBeforeTimeout_eventuallyTimesOut() {
+        // First, display the view
+        val state = getState()
+        underTest.displayView(state)
+
+        // After some time, re-display the view
+        fakeClock.advanceTime(1000L)
+        underTest.displayView(getState())
+
+        // Ensure we still hide the view eventually
+        fakeClock.advanceTime(TIMEOUT_MS + 1)
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun displayScaleChange_viewReinflatedWithMostRecentState() {
+        underTest.displayView(getState(name = "First name"))
+        underTest.displayView(getState(name = "Second name"))
+        reset(windowManager)
+
+        getConfigurationListener().onDensityOrFontScaleChanged()
+
+        verify(windowManager).removeView(any())
+        verify(windowManager).addView(any(), any())
+        assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
+    }
+
+    @Test
+    fun removeView_viewRemovedAndRemovalLogged() {
+        // First, add the view
+        underTest.displayView(getState())
+
+        // Then, remove it
+        val reason = "test reason"
+        underTest.removeView(reason)
+
+        verify(windowManager).removeView(any())
+        verify(logger).logChipRemoval(reason)
+    }
+
+    @Test
+    fun removeView_noAdd_viewNotRemoved() {
+        underTest.removeView("reason")
+
+        verify(windowManager, never()).removeView(any())
+    }
+
+    private fun getState(name: String = "name") = ViewInfo(name)
+
+    private fun getConfigurationListener(): ConfigurationListener {
+        val callbackCaptor = argumentCaptor<ConfigurationListener>()
+        verify(configurationController).addCallback(capture(callbackCaptor))
+        return callbackCaptor.value
+    }
+
+    inner class TestController(
+        context: Context,
+        logger: TemporaryViewLogger,
+        windowManager: WindowManager,
+        @Main mainExecutor: DelayableExecutor,
+        accessibilityManager: AccessibilityManager,
+        configurationController: ConfigurationController,
+        powerManager: PowerManager,
+    ) : TemporaryViewDisplayController<ViewInfo, TemporaryViewLogger>(
+        context,
+        logger,
+        windowManager,
+        mainExecutor,
+        accessibilityManager,
+        configurationController,
+        powerManager,
+        R.layout.media_ttt_chip,
+        "Window Title",
+        "WAKE_REASON",
+    ) {
+        var mostRecentViewInfo: ViewInfo? = null
+
+        override val windowLayoutParams = commonWindowLayoutParams
+        override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) {
+            super.updateView(newInfo, currentView)
+            mostRecentViewInfo = newInfo
+        }
+    }
+
+    inner class ViewInfo(val name: String) : TemporaryViewInfo {
+        override fun getTimeoutMs() = 1L
+    }
+}
+
+private const val TIMEOUT_MS = 10000L
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
new file mode 100644
index 0000000..c9f2b4d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.log.LogcatEchoTracker
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito
+
+@SmallTest
+class TemporaryViewLoggerTest : SysuiTestCase() {
+    private lateinit var buffer: LogBuffer
+    private lateinit var logger: TemporaryViewLogger
+
+    @Before
+    fun setUp() {
+        buffer =
+            LogBufferFactory(DumpManager(), Mockito.mock(LogcatEchoTracker::class.java))
+                .create("buffer", 10)
+        logger = TemporaryViewLogger(buffer, TAG)
+    }
+
+    @Test
+    fun logChipAddition_bufferHasLog() {
+        logger.logChipAddition()
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains(TAG)
+    }
+
+    @Test
+    fun logChipRemoval_bufferHasTagAndReason() {
+        val reason = "test reason"
+        logger.logChipRemoval(reason)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains(TAG)
+        assertThat(actualString).contains(reason)
+    }
+}
+
+private const val TAG = "TestTag"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index f51f783..8645298 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -18,24 +18,28 @@
 
 import android.hardware.devicestate.DeviceStateManager
 import android.hardware.devicestate.DeviceStateManager.FoldStateListener
-import android.os.Handler
 import android.os.PowerManager
 import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.shade.NotificationPanelViewController
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.unfold.util.FoldableDeviceStates
 import com.android.systemui.unfold.util.FoldableTestUtils
+import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.time.FakeSystemClock
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,7 +53,6 @@
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
-@RunWithLooper
 class FoldAodAnimationControllerTest : SysuiTestCase() {
 
     @Mock lateinit var deviceStateManager: DeviceStateManager
@@ -74,26 +77,15 @@
 
     private lateinit var deviceStates: FoldableDeviceStates
 
-    private lateinit var testableLooper: TestableLooper
+    lateinit var keyguardRepository: FakeKeyguardRepository
 
-    lateinit var foldAodAnimationController: FoldAodAnimationController
+    lateinit var underTest: FoldAodAnimationController
+    private val fakeExecutor = FakeExecutor(FakeSystemClock())
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        testableLooper = TestableLooper.get(this)
 
-        foldAodAnimationController =
-            FoldAodAnimationController(
-                    Handler(testableLooper.looper),
-                    context.mainExecutor,
-                    context,
-                    deviceStateManager,
-                    wakefulnessLifecycle,
-                    globalSettings,
-                    latencyTracker,
-                )
-                .apply { initialize(centralSurfaces, lightRevealScrim) }
         deviceStates = FoldableTestUtils.findDeviceStates(context)
 
         whenever(notificationPanelViewController.view).thenReturn(viewGroup)
@@ -107,60 +99,102 @@
                 val onActionStarted = it.arguments[0] as Runnable
                 onActionStarted.run()
             }
-        verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
 
-        foldAodAnimationController.setIsDozing(dozing = true)
-        setAodEnabled(enabled = true)
-        sendFoldEvent(folded = false)
+        keyguardRepository = FakeKeyguardRepository()
+        val keyguardInteractor = KeyguardInteractor(repository = keyguardRepository)
+
+        // Needs to be run on the main thread
+        runBlocking(IMMEDIATE) {
+            underTest =
+                FoldAodAnimationController(
+                        fakeExecutor,
+                        context,
+                        deviceStateManager,
+                        wakefulnessLifecycle,
+                        globalSettings,
+                        latencyTracker,
+                        { keyguardInteractor },
+                    )
+                    .apply { initialize(centralSurfaces, lightRevealScrim) }
+
+            verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
+
+            setAodEnabled(enabled = true)
+            sendFoldEvent(folded = false)
+        }
     }
 
     @Test
-    fun onFolded_aodDisabled_doesNotLogLatency() {
-        setAodEnabled(enabled = false)
+    fun onFolded_aodDisabled_doesNotLogLatency() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozing(this)
+            keyguardRepository.setDozing(true)
+            setAodEnabled(enabled = false)
 
-        fold()
-        simulateScreenTurningOn()
+            yield()
 
-        verifyNoMoreInteractions(latencyTracker)
-    }
+            fold()
+            simulateScreenTurningOn()
+
+            verifyNoMoreInteractions(latencyTracker)
+
+            job.cancel()
+        }
 
     @Test
-    fun onFolded_aodEnabled_logsLatency() {
-        setAodEnabled(enabled = true)
+    fun onFolded_aodEnabled_logsLatency() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozing(this)
+            keyguardRepository.setDozing(true)
+            setAodEnabled(enabled = true)
 
-        fold()
-        simulateScreenTurningOn()
+            yield()
 
-        verify(latencyTracker).onActionStart(any())
-        verify(latencyTracker).onActionEnd(any())
-    }
+            fold()
+            simulateScreenTurningOn()
+
+            verify(latencyTracker).onActionStart(any())
+            verify(latencyTracker).onActionEnd(any())
+
+            job.cancel()
+        }
 
     @Test
-    fun onFolded_animationCancelled_doesNotLogLatency() {
-        setAodEnabled(enabled = true)
+    fun onFolded_animationCancelled_doesNotLogLatency() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozing(this)
+            keyguardRepository.setDozing(true)
+            setAodEnabled(enabled = true)
 
-        fold()
-        foldAodAnimationController.onScreenTurningOn({})
-        foldAodAnimationController.onStartedWakingUp()
-        testableLooper.processAllMessages()
+            yield()
 
-        verify(latencyTracker).onActionStart(any())
-        verify(latencyTracker).onActionCancel(any())
-    }
+            fold()
+            underTest.onScreenTurningOn({})
+            underTest.onStartedWakingUp()
+            fakeExecutor.runAllReady()
+
+            verify(latencyTracker).onActionStart(any())
+            verify(latencyTracker).onActionCancel(any())
+
+            job.cancel()
+        }
 
     private fun simulateScreenTurningOn() {
-        foldAodAnimationController.onScreenTurningOn({})
-        foldAodAnimationController.onScreenTurnedOn()
-        testableLooper.processAllMessages()
+        underTest.onScreenTurningOn({})
+        underTest.onScreenTurnedOn()
+        fakeExecutor.runAllReady()
     }
 
     private fun fold() = sendFoldEvent(folded = true)
 
-    private fun setAodEnabled(enabled: Boolean) =
-        foldAodAnimationController.onAlwaysOnChanged(alwaysOn = enabled)
+    private fun setAodEnabled(enabled: Boolean) = underTest.onAlwaysOnChanged(alwaysOn = enabled)
 
     private fun sendFoldEvent(folded: Boolean) {
         val state = if (folded) deviceStates.folded else deviceStates.unfolded
         foldStateListenerCaptor.value.onStateChanged(state)
     }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
index 66367ec..3968bb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
@@ -16,23 +16,44 @@
 
 package com.android.systemui.user
 
+import android.app.Application
 import android.os.UserManager
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.LayoutInflater
+import android.view.View
+import android.view.Window
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
 import androidx.test.filters.SmallTest
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
+import java.util.concurrent.Executor
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -54,19 +75,49 @@
     private lateinit var userManager: UserManager
     @Mock
     private lateinit var userTracker: UserTracker
+    @Mock
+    private lateinit var flags: FeatureFlags
+    @Mock
+    private lateinit var viewModelFactoryLazy: dagger.Lazy<UserSwitcherViewModel.Factory>
+    @Mock
+    private lateinit var onBackDispatcher: OnBackInvokedDispatcher
+    @Mock
+    private lateinit var decorView: View
+    @Mock
+    private lateinit var window: Window
+    @Mock
+    private lateinit var userSwitcherRootView: UserSwitcherRootView
+    @Captor
+    private lateinit var onBackInvokedCallback: ArgumentCaptor<OnBackInvokedCallback>
+    var isFinished = false
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        activity = UserSwitcherActivity(
+        activity = spy(object : UserSwitcherActivity(
             userSwitcherController,
             broadcastDispatcher,
-            layoutInflater,
             falsingCollector,
             falsingManager,
             userManager,
-            userTracker
-        )
+            userTracker,
+            flags,
+            viewModelFactoryLazy,
+        ) {
+            override fun getOnBackInvokedDispatcher() = onBackDispatcher
+            override fun getMainExecutor(): Executor = FakeExecutor(FakeSystemClock())
+            override fun finish() {
+                isFinished = true
+            }
+        })
+        `when`(activity.window).thenReturn(window)
+        `when`(window.decorView).thenReturn(decorView)
+        `when`(activity.findViewById<UserSwitcherRootView>(R.id.user_switcher_root))
+                .thenReturn(userSwitcherRootView)
+        `when`(activity.findViewById<View>(R.id.cancel)).thenReturn(mock(View::class.java))
+        `when`(activity.findViewById<View>(R.id.add)).thenReturn(mock(View::class.java))
+        `when`(activity.application).thenReturn(mock(Application::class.java))
+        doNothing().`when`(activity).setContentView(anyInt())
     }
 
     @Test
@@ -78,4 +129,24 @@
         assertThat(activity.getMaxColumns(7)).isEqualTo(4)
         assertThat(activity.getMaxColumns(9)).isEqualTo(5)
     }
+
+    @Test
+    fun onCreate_callbackRegistration() {
+        activity.createActivity()
+        verify(onBackDispatcher).registerOnBackInvokedCallback(
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any())
+
+        activity.destroyActivity()
+        verify(onBackDispatcher).unregisterOnBackInvokedCallback(any())
+    }
+
+    @Test
+    fun onBackInvokedCallback_finishesActivity() {
+        activity.createActivity()
+        verify(onBackDispatcher).registerOnBackInvokedCallback(
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), onBackInvokedCallback.capture())
+
+        onBackInvokedCallback.value.onBackInvoked()
+        assertThat(isFinished).isTrue()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
new file mode 100644
index 0000000..6b466e1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.data.repository
+
+import android.content.pm.UserInfo
+import android.os.UserManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserRepositoryImplTest : SysuiTestCase() {
+
+    @Mock private lateinit var manager: UserManager
+    @Mock private lateinit var controller: UserSwitcherController
+    @Captor
+    private lateinit var userSwitchCallbackCaptor:
+        ArgumentCaptor<UserSwitcherController.UserSwitchCallback>
+
+    private lateinit var underTest: UserRepositoryImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(controller.addUsersFromLockScreen).thenReturn(MutableStateFlow(false))
+        whenever(controller.isGuestUserAutoCreated).thenReturn(false)
+        whenever(controller.isGuestUserResetting).thenReturn(false)
+
+        underTest =
+            UserRepositoryImpl(
+                appContext = context,
+                manager = manager,
+                controller = controller,
+            )
+    }
+
+    @Test
+    fun `users - registers for updates`() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.users.onEach {}.launchIn(this)
+
+            verify(controller).addUserSwitchCallback(any())
+
+            job.cancel()
+        }
+
+    @Test
+    fun `users - unregisters from updates`() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.users.onEach {}.launchIn(this)
+            verify(controller).addUserSwitchCallback(capture(userSwitchCallbackCaptor))
+
+            job.cancel()
+
+            verify(controller).removeUserSwitchCallback(userSwitchCallbackCaptor.value)
+        }
+
+    @Test
+    fun `users - does not include actions`() =
+        runBlocking(IMMEDIATE) {
+            whenever(controller.users)
+                .thenReturn(
+                    arrayListOf(
+                        createUserRecord(0, isSelected = true),
+                        createActionRecord(UserActionModel.ADD_USER),
+                        createUserRecord(1),
+                        createUserRecord(2),
+                        createActionRecord(UserActionModel.ADD_SUPERVISED_USER),
+                        createActionRecord(UserActionModel.ENTER_GUEST_MODE),
+                    )
+                )
+            var models: List<UserModel>? = null
+            val job = underTest.users.onEach { models = it }.launchIn(this)
+
+            assertThat(models).hasSize(3)
+            assertThat(models?.get(0)?.id).isEqualTo(0)
+            assertThat(models?.get(0)?.isSelected).isTrue()
+            assertThat(models?.get(1)?.id).isEqualTo(1)
+            assertThat(models?.get(1)?.isSelected).isFalse()
+            assertThat(models?.get(2)?.id).isEqualTo(2)
+            assertThat(models?.get(2)?.isSelected).isFalse()
+            job.cancel()
+        }
+
+    @Test
+    fun selectedUser() =
+        runBlocking(IMMEDIATE) {
+            whenever(controller.users)
+                .thenReturn(
+                    arrayListOf(
+                        createUserRecord(0, isSelected = true),
+                        createUserRecord(1),
+                        createUserRecord(2),
+                    )
+                )
+            var id: Int? = null
+            val job = underTest.selectedUser.map { it.id }.onEach { id = it }.launchIn(this)
+
+            assertThat(id).isEqualTo(0)
+
+            whenever(controller.users)
+                .thenReturn(
+                    arrayListOf(
+                        createUserRecord(0),
+                        createUserRecord(1),
+                        createUserRecord(2, isSelected = true),
+                    )
+                )
+            verify(controller).addUserSwitchCallback(capture(userSwitchCallbackCaptor))
+            userSwitchCallbackCaptor.value.onUserSwitched()
+            assertThat(id).isEqualTo(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - unregisters from updates`() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.actions.onEach {}.launchIn(this)
+            verify(controller).addUserSwitchCallback(capture(userSwitchCallbackCaptor))
+
+            job.cancel()
+
+            verify(controller).removeUserSwitchCallback(userSwitchCallbackCaptor.value)
+        }
+
+    @Test
+    fun `actions - registers for updates`() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.actions.onEach {}.launchIn(this)
+
+            verify(controller).addUserSwitchCallback(any())
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actopms - does not include users`() =
+        runBlocking(IMMEDIATE) {
+            whenever(controller.users)
+                .thenReturn(
+                    arrayListOf(
+                        createUserRecord(0, isSelected = true),
+                        createActionRecord(UserActionModel.ADD_USER),
+                        createUserRecord(1),
+                        createUserRecord(2),
+                        createActionRecord(UserActionModel.ADD_SUPERVISED_USER),
+                        createActionRecord(UserActionModel.ENTER_GUEST_MODE),
+                    )
+                )
+            var models: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { models = it }.launchIn(this)
+
+            assertThat(models).hasSize(3)
+            assertThat(models?.get(0)).isEqualTo(UserActionModel.ADD_USER)
+            assertThat(models?.get(1)).isEqualTo(UserActionModel.ADD_SUPERVISED_USER)
+            assertThat(models?.get(2)).isEqualTo(UserActionModel.ENTER_GUEST_MODE)
+            job.cancel()
+        }
+
+    private fun createUserRecord(id: Int, isSelected: Boolean = false): UserRecord {
+        return UserRecord(
+            info = UserInfo(id, "name$id", 0),
+            isCurrent = isSelected,
+        )
+    }
+
+    private fun createActionRecord(action: UserActionModel): UserRecord {
+        return UserRecord(
+            isAddUser = action == UserActionModel.ADD_USER,
+            isAddSupervisedUser = action == UserActionModel.ADD_SUPERVISED_USER,
+            isGuest = action == UserActionModel.ENTER_GUEST_MODE,
+        )
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
new file mode 100644
index 0000000..e914e2e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserInteractorTest : SysuiTestCase() {
+
+    @Mock private lateinit var controller: UserSwitcherController
+    @Mock private lateinit var activityStarter: ActivityStarter
+
+    private lateinit var underTest: UserInteractor
+
+    private lateinit var userRepository: FakeUserRepository
+    private lateinit var keyguardRepository: FakeKeyguardRepository
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        userRepository = FakeUserRepository()
+        keyguardRepository = FakeKeyguardRepository()
+        underTest =
+            UserInteractor(
+                repository = userRepository,
+                controller = controller,
+                activityStarter = activityStarter,
+                keyguardInteractor =
+                    KeyguardInteractor(
+                        repository = keyguardRepository,
+                    ),
+            )
+    }
+
+    @Test
+    fun `actions - not actionable when locked and locked - no actions`() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(UserActionModel.values().toList())
+            userRepository.setActionableWhenLocked(false)
+            keyguardRepository.setKeyguardShowing(true)
+
+            var actions: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+            assertThat(actions).isEmpty()
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - not actionable when locked and not locked`() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(
+                listOf(
+                    UserActionModel.ENTER_GUEST_MODE,
+                    UserActionModel.ADD_USER,
+                    UserActionModel.ADD_SUPERVISED_USER,
+                )
+            )
+            userRepository.setActionableWhenLocked(false)
+            keyguardRepository.setKeyguardShowing(false)
+
+            var actions: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+            assertThat(actions)
+                .isEqualTo(
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.ADD_USER,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+                    )
+                )
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - actionable when locked and not locked`() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(
+                listOf(
+                    UserActionModel.ENTER_GUEST_MODE,
+                    UserActionModel.ADD_USER,
+                    UserActionModel.ADD_SUPERVISED_USER,
+                )
+            )
+            userRepository.setActionableWhenLocked(true)
+            keyguardRepository.setKeyguardShowing(false)
+
+            var actions: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+            assertThat(actions)
+                .isEqualTo(
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.ADD_USER,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+                    )
+                )
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - actionable when locked and locked`() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(
+                listOf(
+                    UserActionModel.ENTER_GUEST_MODE,
+                    UserActionModel.ADD_USER,
+                    UserActionModel.ADD_SUPERVISED_USER,
+                )
+            )
+            userRepository.setActionableWhenLocked(true)
+            keyguardRepository.setKeyguardShowing(true)
+
+            var actions: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { actions = it }.launchIn(this)
+
+            assertThat(actions)
+                .isEqualTo(
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.ADD_USER,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                        UserActionModel.NAVIGATE_TO_USER_MANAGEMENT,
+                    )
+                )
+            job.cancel()
+        }
+
+    @Test
+    fun selectUser() {
+        val userId = 3
+
+        underTest.selectUser(userId)
+
+        verify(controller).onUserSelected(eq(userId), nullable())
+    }
+
+    @Test
+    fun `executeAction - guest`() {
+        underTest.executeAction(UserActionModel.ENTER_GUEST_MODE)
+
+        verify(controller).createAndSwitchToGuestUser(nullable())
+    }
+
+    @Test
+    fun `executeAction - add user`() {
+        underTest.executeAction(UserActionModel.ADD_USER)
+
+        verify(controller).showAddUserDialog(nullable())
+    }
+
+    @Test
+    fun `executeAction - add supervised user`() {
+        underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
+
+        verify(controller).startSupervisedUserActivity()
+    }
+
+    @Test
+    fun `executeAction - manage users`() {
+        underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
+
+        verify(activityStarter).startActivity(any(), anyBoolean())
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
new file mode 100644
index 0000000..ef4500d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserSwitcherViewModelTest : SysuiTestCase() {
+
+    @Mock private lateinit var controller: UserSwitcherController
+    @Mock private lateinit var activityStarter: ActivityStarter
+
+    private lateinit var underTest: UserSwitcherViewModel
+
+    private lateinit var userRepository: FakeUserRepository
+    private lateinit var keyguardRepository: FakeKeyguardRepository
+    private lateinit var powerRepository: FakePowerRepository
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        userRepository = FakeUserRepository()
+        keyguardRepository = FakeKeyguardRepository()
+        powerRepository = FakePowerRepository()
+        underTest =
+            UserSwitcherViewModel.Factory(
+                    userInteractor =
+                        UserInteractor(
+                            repository = userRepository,
+                            controller = controller,
+                            activityStarter = activityStarter,
+                            keyguardInteractor =
+                                KeyguardInteractor(
+                                    repository = keyguardRepository,
+                                )
+                        ),
+                    powerInteractor =
+                        PowerInteractor(
+                            repository = powerRepository,
+                        ),
+                )
+                .create(UserSwitcherViewModel::class.java)
+    }
+
+    @Test
+    fun users() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setUsers(
+                listOf(
+                    UserModel(
+                        id = 0,
+                        name = Text.Loaded("zero"),
+                        image = USER_IMAGE,
+                        isSelected = true,
+                        isSelectable = true,
+                    ),
+                    UserModel(
+                        id = 1,
+                        name = Text.Loaded("one"),
+                        image = USER_IMAGE,
+                        isSelected = false,
+                        isSelectable = true,
+                    ),
+                    UserModel(
+                        id = 2,
+                        name = Text.Loaded("two"),
+                        image = USER_IMAGE,
+                        isSelected = false,
+                        isSelectable = false,
+                    ),
+                )
+            )
+
+            var userViewModels: List<UserViewModel>? = null
+            val job = underTest.users.onEach { userViewModels = it }.launchIn(this)
+
+            assertThat(userViewModels).hasSize(3)
+            assertUserViewModel(
+                viewModel = userViewModels?.get(0),
+                viewKey = 0,
+                name = "zero",
+                isSelectionMarkerVisible = true,
+                alpha = LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA,
+                isClickable = true,
+            )
+            assertUserViewModel(
+                viewModel = userViewModels?.get(1),
+                viewKey = 1,
+                name = "one",
+                isSelectionMarkerVisible = false,
+                alpha = LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA,
+                isClickable = true,
+            )
+            assertUserViewModel(
+                viewModel = userViewModels?.get(2),
+                viewKey = 2,
+                name = "two",
+                isSelectionMarkerVisible = false,
+                alpha = LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA,
+                isClickable = false,
+            )
+            job.cancel()
+        }
+
+    @Test
+    fun `maximumUserColumns - few users`() =
+        runBlocking(IMMEDIATE) {
+            setUsers(count = 2)
+            var value: Int? = null
+            val job = underTest.maximumUserColumns.onEach { value = it }.launchIn(this)
+
+            assertThat(value).isEqualTo(4)
+            job.cancel()
+        }
+
+    @Test
+    fun `maximumUserColumns - many users`() =
+        runBlocking(IMMEDIATE) {
+            setUsers(count = 5)
+            var value: Int? = null
+            val job = underTest.maximumUserColumns.onEach { value = it }.launchIn(this)
+
+            assertThat(value).isEqualTo(3)
+            job.cancel()
+        }
+
+    @Test
+    fun `isOpenMenuButtonVisible - has actions - true`() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(UserActionModel.values().toList())
+
+            var isVisible: Boolean? = null
+            val job = underTest.isOpenMenuButtonVisible.onEach { isVisible = it }.launchIn(this)
+
+            assertThat(isVisible).isTrue()
+            job.cancel()
+        }
+
+    @Test
+    fun `isOpenMenuButtonVisible - no actions - false`() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(emptyList())
+
+            var isVisible: Boolean? = null
+            val job = underTest.isOpenMenuButtonVisible.onEach { isVisible = it }.launchIn(this)
+
+            assertThat(isVisible).isFalse()
+            job.cancel()
+        }
+
+    @Test
+    fun menu() =
+        runBlocking(IMMEDIATE) {
+            userRepository.setActions(UserActionModel.values().toList())
+            var isMenuVisible: Boolean? = null
+            val job = underTest.isMenuVisible.onEach { isMenuVisible = it }.launchIn(this)
+            assertThat(isMenuVisible).isFalse()
+
+            underTest.onOpenMenuButtonClicked()
+            assertThat(isMenuVisible).isTrue()
+
+            underTest.onMenuClosed()
+            assertThat(isMenuVisible).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun `isFinishRequested - finishes when user is switched`() =
+        runBlocking(IMMEDIATE) {
+            setUsers(count = 2)
+            var isFinishRequested: Boolean? = null
+            val job = underTest.isFinishRequested.onEach { isFinishRequested = it }.launchIn(this)
+            assertThat(isFinishRequested).isFalse()
+
+            userRepository.setSelectedUser(1)
+            yield()
+            assertThat(isFinishRequested).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun `isFinishRequested - finishes when the screen turns off`() =
+        runBlocking(IMMEDIATE) {
+            setUsers(count = 2)
+            powerRepository.setInteractive(true)
+            var isFinishRequested: Boolean? = null
+            val job = underTest.isFinishRequested.onEach { isFinishRequested = it }.launchIn(this)
+            assertThat(isFinishRequested).isFalse()
+
+            powerRepository.setInteractive(false)
+            yield()
+            assertThat(isFinishRequested).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun `isFinishRequested - finishes when cancel button is clicked`() =
+        runBlocking(IMMEDIATE) {
+            setUsers(count = 2)
+            powerRepository.setInteractive(true)
+            var isFinishRequested: Boolean? = null
+            val job = underTest.isFinishRequested.onEach { isFinishRequested = it }.launchIn(this)
+            assertThat(isFinishRequested).isFalse()
+
+            underTest.onCancelButtonClicked()
+            yield()
+            assertThat(isFinishRequested).isTrue()
+
+            underTest.onFinished()
+            yield()
+            assertThat(isFinishRequested).isFalse()
+
+            job.cancel()
+        }
+
+    private fun setUsers(count: Int) {
+        userRepository.setUsers(
+            (0 until count).map { index ->
+                UserModel(
+                    id = index,
+                    name = Text.Loaded("$index"),
+                    image = USER_IMAGE,
+                    isSelected = index == 0,
+                    isSelectable = true,
+                )
+            }
+        )
+    }
+
+    private fun assertUserViewModel(
+        viewModel: UserViewModel?,
+        viewKey: Int,
+        name: String,
+        isSelectionMarkerVisible: Boolean,
+        alpha: Float,
+        isClickable: Boolean,
+    ) {
+        checkNotNull(viewModel)
+        assertThat(viewModel.viewKey).isEqualTo(viewKey)
+        assertThat(viewModel.name).isEqualTo(Text.Loaded(name))
+        assertThat(viewModel.isSelectionMarkerVisible).isEqualTo(isSelectionMarkerVisible)
+        assertThat(viewModel.alpha).isEqualTo(alpha)
+        assertThat(viewModel.onClicked != null).isEqualTo(isClickable)
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+        private val USER_IMAGE = mock<Drawable>()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 092e82c..7df7077 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -28,12 +28,14 @@
 import kotlinx.coroutines.flow.asFlow
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.takeWhile
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -127,6 +129,53 @@
                 )
             )
     }
+
+    @Test
+    fun dontEmitFirstEvent() = runBlocking {
+        assertThatFlow(flowOf(setOf(1, 2), setOf(2, 3)).setChanges(emitFirstEvent = false))
+            .emitsExactly(
+                SetChanges(
+                    removed = setOf(1),
+                    added = setOf(3),
+                )
+            )
+    }
+}
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SampleFlowTest : SysuiTestCase() {
+    @Test
+    fun simple() = runBlocking {
+        assertThatFlow(flow { yield(); emit(1) }.sample(flowOf(2)) { a, b -> a to b })
+            .emitsExactly(1 to 2)
+    }
+
+    @Test
+    fun otherFlowNoValueYet() = runBlocking {
+        assertThatFlow(flowOf(1).sample(emptyFlow<Unit>()))
+            .emitsNothing()
+    }
+
+    @Test
+    fun multipleSamples() = runBlocking {
+        val samplee = MutableSharedFlow<Int>()
+        val sampler = flow {
+            emit(1)
+            samplee.emit(1)
+            emit(2)
+            samplee.emit(2)
+            samplee.emit(3)
+            emit(3)
+            emit(4)
+        }
+        assertThatFlow(sampler.sample(samplee) { a, b -> a to b })
+            .emitsExactly(
+                2 to 1,
+                3 to 3,
+                4 to 3,
+            )
+    }
 }
 
 private fun <T> assertThatFlow(flow: Flow<T>) = object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
new file mode 100644
index 0000000..6848b83
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RaceSuspendTest : SysuiTestCase() {
+    @Test
+    fun raceSimple() = runBlocking {
+        val winner = CompletableDeferred<Int>()
+        val result = async {
+            race(
+                { winner.await() },
+                { awaitCancellation() },
+            )
+        }
+        winner.complete(1)
+        assertThat(result.await()).isEqualTo(1)
+    }
+
+    @Test
+    fun raceImmediate() = runBlocking {
+        assertThat(
+            race<Int>(
+                { 1 },
+                { 2 },
+            )
+        ).isEqualTo(1)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index e1ddaad..e47acd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui;
+package com.android.systemui.wallpapers;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -40,7 +40,8 @@
 import android.view.DisplayInfo;
 import android.view.SurfaceHolder;
 
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
 
 import org.junit.Before;
 import org.junit.Ignore;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
index a3221b5..a42bade 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/EglHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/EglHelperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
index 510b907..89b2222 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/glwallpaper/ImageWallpaperRendererTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/gl/ImageWallpaperRendererTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.glwallpaper;
+package com.android.systemui.wallpapers.gl;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 11eb4e3..42b434a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -12,6 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
 package com.android.systemui.keyguard.data.repository
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
new file mode 100644
index 0000000..15465f4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.power.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakePowerRepository(
+    initialInteractive: Boolean = true,
+) : PowerRepository {
+
+    private val _isInteractive = MutableStateFlow(initialInteractive)
+    override val isInteractive: Flow<Boolean> = _isInteractive.asStateFlow()
+
+    fun setInteractive(value: Boolean) {
+        _isInteractive.value = value
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
new file mode 100644
index 0000000..20f1e36
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.data.repository
+
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeUserRepository : UserRepository {
+
+    private val _users = MutableStateFlow<List<UserModel>>(emptyList())
+    override val users: Flow<List<UserModel>> = _users.asStateFlow()
+    override val selectedUser: Flow<UserModel> =
+        users.map { models -> models.first { model -> model.isSelected } }
+
+    private val _actions = MutableStateFlow<List<UserActionModel>>(emptyList())
+    override val actions: Flow<List<UserActionModel>> = _actions.asStateFlow()
+
+    private val _isActionableWhenLocked = MutableStateFlow(false)
+    override val isActionableWhenLocked: Flow<Boolean> = _isActionableWhenLocked.asStateFlow()
+
+    private var _isGuestUserAutoCreated: Boolean = false
+    override val isGuestUserAutoCreated: Boolean
+        get() = _isGuestUserAutoCreated
+    private var _isGuestUserResetting: Boolean = false
+    override val isGuestUserResetting: Boolean
+        get() = _isGuestUserResetting
+
+    fun setUsers(models: List<UserModel>) {
+        _users.value = models
+    }
+
+    fun setSelectedUser(userId: Int) {
+        check(_users.value.find { it.id == userId } != null) {
+            "Cannot select a user with ID $userId - no user with that ID found!"
+        }
+
+        setUsers(
+            _users.value.map { model ->
+                when {
+                    model.isSelected && model.id != userId -> model.copy(isSelected = false)
+                    !model.isSelected && model.id == userId -> model.copy(isSelected = true)
+                    else -> model
+                }
+            }
+        )
+    }
+
+    fun setActions(models: List<UserActionModel>) {
+        _actions.value = models
+    }
+
+    fun setActionableWhenLocked(value: Boolean) {
+        _isActionableWhenLocked.value = value
+    }
+
+    fun setGuestUserAutoCreated(value: Boolean) {
+        _isGuestUserAutoCreated = value
+    }
+
+    fun setGuestUserResetting(value: Boolean) {
+        _isGuestUserResetting = value
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index f539dbd..8d171be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -26,6 +26,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatcher
 import org.mockito.Mockito
+import org.mockito.stubbing.OngoingStubbing
 
 /**
  * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
@@ -77,8 +78,18 @@
  * Helper function for creating new mocks, without the need to pass in a [Class] instance.
  *
  * Generic T is nullable because implicitly bounded by Any?.
+ *
+ * @param apply builder function to simplify stub configuration by improving type inference.
  */
-inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
+inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java)
+        .apply(apply)
+
+/**
+ * Helper function for stubbing methods without the need to use backticks.
+ *
+ * @see Mockito.when
+ */
+fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
 
 /**
  * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
@@ -118,3 +129,17 @@
  */
 inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
         kotlinArgumentCaptor<T>().apply { block() }.value
+
+/**
+ * Variant of [withArgCaptor] for capturing multiple arguments.
+ *
+ *    val captor = argumentCaptor<Foo>()
+ *    verify(...).someMethod(captor.capture())
+ *    val captured: List<Foo> = captor.allValues
+ *
+ * becomes:
+ *
+ *    val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) }
+ */
+inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> =
+        kotlinArgumentCaptor<T>().apply{ block() }.allValues
diff --git a/services/Android.bp b/services/Android.bp
index 4f80a98..decfa77 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -57,6 +57,7 @@
                 // retracing infra.
                 optimize: false,
                 shrink: true,
+                ignore_warnings: false,
                 proguard_flags_files: ["proguard.flags"],
             },
             // Note: Optimizations are disabled by default if unspecified in
@@ -175,6 +176,8 @@
         "android.hidl.manager-V1.0-java",
         "framework-tethering.stubs.module_lib",
         "service-art.stubs.system_server",
+        "service-permission.stubs.system_server",
+        "service-sdksandbox.stubs.system_server",
     ],
 
     // Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 3324c52..799c759 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -75,7 +75,6 @@
 import android.view.Display;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
-import android.view.SurfaceControl.ScreenshotHardwareBuffer;
 import android.view.View;
 import android.view.WindowInfo;
 import android.view.accessibility.AccessibilityCache;
@@ -84,6 +83,7 @@
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 import android.view.inputmethod.EditorInfo;
+import android.window.ScreenCapture.ScreenshotHardwareBuffer;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.compat.IPlatformCompat;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 990e963..f55cfb1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -957,10 +957,11 @@
             // current state of the windows as the window manager may be delaying
             // the computation for performance reasons.
             boolean shouldComputeWindows = false;
-            int displayId = Display.INVALID_DISPLAY;
+            int displayId = event.getDisplayId();
             synchronized (mLock) {
                 final int windowId = event.getWindowId();
-                if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+                if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID
+                        && displayId == Display.INVALID_DISPLAY) {
                     displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(
                             resolvedUserId, windowId);
                     event.setDisplayId(displayId);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index d33e7b2..7c68c8a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -19,7 +19,6 @@
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION;
 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -275,22 +274,23 @@
          * Sets the active flag of the window according to given windowId, others set to inactive.
          *
          * @param windowId The windowId
+         * @return {@code true} if the window is in this display, {@code false} otherwise.
          */
-        void setActiveWindowLocked(int windowId) {
+        boolean setActiveWindowLocked(int windowId) {
+            boolean foundWindow = false;
             if (mWindows != null) {
                 final int windowCount = mWindows.size();
                 for (int i = 0; i < windowCount; i++) {
                     AccessibilityWindowInfo window = mWindows.get(i);
                     if (window.getId() == windowId) {
                         window.setActive(true);
-                        mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
-                                AccessibilityEvent.obtainWindowsChangedEvent(windowId,
-                                        AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
+                        foundWindow = true;
                     } else {
                         window.setActive(false);
                     }
                 }
             }
+            return foundWindow;
         }
 
         /**
@@ -298,24 +298,23 @@
          * unfocused.
          *
          * @param windowId The windowId
+         * @return {@code true} if the window is in this display, {@code false} otherwise.
          */
-        void setAccessibilityFocusedWindowLocked(int windowId) {
+        boolean setAccessibilityFocusedWindowLocked(int windowId) {
+            boolean foundWindow = false;
             if (mWindows != null) {
                 final int windowCount = mWindows.size();
                 for (int i = 0; i < windowCount; i++) {
                     AccessibilityWindowInfo window = mWindows.get(i);
                     if (window.getId() == windowId) {
-                        mAccessibilityFocusedDisplayId = mDisplayId;
                         window.setAccessibilityFocused(true);
-                        mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
-                                AccessibilityEvent.obtainWindowsChangedEvent(
-                                        windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
-
+                        foundWindow = true;
                     } else {
                         window.setAccessibilityFocused(false);
                     }
                 }
             }
+            return foundWindow;
         }
 
         /**
@@ -704,7 +703,7 @@
                 final AccessibilityWindowInfo window = oldWindows.get(i);
                 if (mA11yWindowInfoById.get(window.getId()) == null) {
                     events.add(AccessibilityEvent.obtainWindowsChangedEvent(
-                            window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
+                            mDisplayId, window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
                 }
             }
 
@@ -714,13 +713,13 @@
                 final AccessibilityWindowInfo newWindow = mWindows.get(i);
                 final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId());
                 if (oldWindow == null) {
-                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(mDisplayId,
                             newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED));
                 } else {
                     int changes = newWindow.differenceFrom(oldWindow);
                     if (changes !=  0) {
                         events.add(AccessibilityEvent.obtainWindowsChangedEvent(
-                                newWindow.getId(), changes));
+                                mDisplayId, newWindow.getId(), changes));
                     }
                 }
             }
@@ -1522,38 +1521,59 @@
 
     private void setActiveWindowLocked(int windowId) {
         if (mActiveWindowId != windowId) {
-            mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
-                    AccessibilityEvent.obtainWindowsChangedEvent(
+            List<AccessibilityEvent> events = new ArrayList<>(2);
+            if (mActiveWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+                final DisplayWindowsObserver observer =
+                        getDisplayWindowObserverByWindowIdLocked(mActiveWindowId);
+                if (observer != null) {
+                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
                             mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
+                }
+            }
 
             mActiveWindowId = windowId;
             // Goes through all windows for each display.
             final int count = mDisplayWindowsObservers.size();
             for (int i = 0; i < count; i++) {
                 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
-                if (observer != null) {
-                    observer.setActiveWindowLocked(windowId);
+                if (observer != null && observer.setActiveWindowLocked(windowId)) {
+                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
+                            windowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
                 }
             }
+
+            for (final AccessibilityEvent event : events) {
+                mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(event);
+            }
         }
     }
 
     private void setAccessibilityFocusedWindowLocked(int windowId) {
         if (mAccessibilityFocusedWindowId != windowId) {
-            mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
-                    AccessibilityEvent.obtainWindowsChangedEvent(
-                            mAccessibilityFocusedWindowId,
-                            WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
+            List<AccessibilityEvent> events = new ArrayList<>(2);
+            if (mAccessibilityFocusedDisplayId != Display.INVALID_DISPLAY
+                    && mAccessibilityFocusedWindowId
+                    != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+                events.add(AccessibilityEvent.obtainWindowsChangedEvent(
+                        mAccessibilityFocusedDisplayId, mAccessibilityFocusedWindowId,
+                        AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
+            }
 
             mAccessibilityFocusedWindowId = windowId;
             // Goes through all windows for each display.
             final int count = mDisplayWindowsObservers.size();
             for (int i = 0; i < count; i++) {
                 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
-                if (observer != null) {
-                    observer.setAccessibilityFocusedWindowLocked(windowId);
+                if (observer != null && observer.setAccessibilityFocusedWindowLocked(windowId)) {
+                    mAccessibilityFocusedDisplayId = observer.mDisplayId;
+                    events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
+                            windowId, AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
                 }
             }
+
+            for (final AccessibilityEvent event : events) {
+                mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(event);
+            }
         }
     }
 
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index b3314ed..dc9144a 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -107,7 +107,7 @@
  */
 @SuppressLint("LongLogTag")
 class AssociationRequestsProcessor {
-    private static final String TAG = "CompanionDevice_AssociationRequestsProcessor";
+    private static final String TAG = "CDM_AssociationRequestsProcessor";
 
     private static final ComponentName ASSOCIATION_REQUEST_APPROVAL_ACTIVITY =
             createRelative(COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, ".CompanionDeviceActivity");
diff --git a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
index d5991d3..8c6ad3b 100644
--- a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
+++ b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
@@ -58,7 +58,7 @@
 @SuppressLint("LongLogTag")
 class AssociationStoreImpl implements AssociationStore {
     private static final boolean DEBUG = false;
-    private static final String TAG = "CompanionDevice_AssociationStore";
+    private static final String TAG = "CDM_AssociationStore";
 
     private final Object mLock = new Object();
 
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index 4f15691..3814591 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -66,7 +66,7 @@
 @SuppressLint("LongLogTag")
 public class CompanionApplicationController {
     static final boolean DEBUG = false;
-    private static final String TAG = "CompanionDevice_ApplicationController";
+    private static final String TAG = "CDM_CompanionApplicationController";
 
     private static final long REBIND_TIMEOUT = 10 * 1000; // 10 sec
 
@@ -256,6 +256,9 @@
             return;
         }
 
+        Log.i(TAG, "Calling onDeviceAppeared to userId=[" + userId + "] package=["
+                + packageName + "] associationId=[" + association.getId() + "]");
+
         primaryServiceConnector.postOnDeviceAppeared(association);
     }
 
@@ -278,6 +281,9 @@
             return;
         }
 
+        Log.i(TAG, "Calling onDeviceDisappeared to userId=[" + userId + "] package=["
+                + packageName + "] associationId=[" + association.getId() + "]");
+
         primaryServiceConnector.postOnDeviceDisappeared(association);
     }
 
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 1af2ca1..85d3140 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -124,7 +124,7 @@
 
 @SuppressLint("LongLogTag")
 public class CompanionDeviceManagerService extends SystemService {
-    static final String TAG = "CompanionDeviceManagerService";
+    static final String TAG = "CDM_CompanionDeviceManagerService";
     static final boolean DEBUG = false;
 
     /** Range of Association IDs allocated for a user.*/
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index fa1d107..93cc611 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -43,7 +43,7 @@
  */
 @SuppressLint("LongLogTag")
 class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
-    private static final String TAG = "CompanionDevice_ServiceConnector";
+    private static final String TAG = "CDM_CompanionServiceConnector";
     private static final boolean DEBUG = false;
 
     /** Listener for changes to the state of the {@link CompanionDeviceServiceConnector}  */
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 322ad46..d24f9e3 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -26,7 +26,7 @@
 import java.util.List;
 
 class CompanionDeviceShellCommand extends ShellCommand {
-    private static final String TAG = "CompanionDevice_ShellCommand";
+    private static final String TAG = "CDM_CompanionDeviceShellCommand";
 
     private final CompanionDeviceManagerService mService;
     private final AssociationStore mAssociationStore;
diff --git a/services/companion/java/com/android/server/companion/DataStoreUtils.java b/services/companion/java/com/android/server/companion/DataStoreUtils.java
index 73e68ec..c182529 100644
--- a/services/companion/java/com/android/server/companion/DataStoreUtils.java
+++ b/services/companion/java/com/android/server/companion/DataStoreUtils.java
@@ -37,7 +37,7 @@
  * Util class for CDM data stores
  */
 public final class DataStoreUtils {
-    private static final String TAG = "CompanionDevice_DataStoreUtils";
+    private static final String TAG = "CDM_DataStoreUtils";
 
     /**
      * Check if the parser pointer is at the start of the tag
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index be81b67..9f27f72 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -63,7 +63,7 @@
  */
 public class SystemDataTransferProcessor {
 
-    private static final String LOG_TAG = SystemDataTransferProcessor.class.getSimpleName();
+    private static final String LOG_TAG = "CDM_SystemDataTransferProcessor";
 
     // Values from UI to SystemDataTransferProcessor via ResultReceiver
     private static final int RESULT_CODE_SYSTEM_DATA_TRANSFER_ALLOWED = 0;
@@ -150,8 +150,9 @@
         // Create a PendingIntent
         final long token = Binder.clearCallingIdentity();
         try {
-            return PendingIntent.getActivity(mContext, /*requestCode */ associationId, intent,
-                    FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
+            return PendingIntent.getActivityAsUser(mContext, /*requestCode */ associationId, intent,
+                    FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE, /* options= */ null,
+                    UserHandle.CURRENT);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
index ab0a062..dbff628 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferRequestStore.java
@@ -75,7 +75,7 @@
  */
 public class SystemDataTransferRequestStore {
 
-    private static final String LOG_TAG = SystemDataTransferRequestStore.class.getSimpleName();
+    private static final String LOG_TAG = "CDM_SystemDataTransferRequestStore";
 
     private static final String FILE_NAME = "companion_device_system_data_transfer_requests.xml";
 
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index ad09f7c..0aaa523 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -71,7 +71,7 @@
 
 @SuppressLint("LongLogTag")
 class BleCompanionDeviceScanner implements AssociationStore.OnChangeListener {
-    private static final String TAG = "CompanionDevice_PresenceMonitor_BLE";
+    private static final String TAG = "CDM_BleCompanionDeviceScanner";
 
     /**
      * When using {@link ScanSettings#SCAN_MODE_LOW_POWER}, it usually takes from 20 seconds to
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index 823743d..f6b99b5 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -40,7 +40,7 @@
 class BluetoothCompanionDeviceConnectionListener
         extends BluetoothAdapter.BluetoothConnectionCallback
         implements AssociationStore.OnChangeListener {
-    private static final String TAG = "CompanionDevice_PresenceMonitor_BT";
+    private static final String TAG = "CDM_BluetoothCompanionDeviceConnectionListener";
 
     interface Callback {
         void onBluetoothCompanionDeviceConnected(int associationId);
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 0e4870a..fb8c5b1 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -57,7 +57,7 @@
 public class CompanionDevicePresenceMonitor implements AssociationStore.OnChangeListener,
         BluetoothCompanionDeviceConnectionListener.Callback, BleCompanionDeviceScanner.Callback {
     static final boolean DEBUG = false;
-    private static final String TAG = "CompanionDevice_PresenceMonitor";
+    private static final String TAG = "CDM_CompanionDevicePresenceMonitor";
 
     /** Callback for notifying about changes to status of companion devices. */
     public interface Callback {
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index 77d51ea..6db99a0 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -49,7 +49,7 @@
 
 @SuppressLint("LongLogTag")
 public class CompanionTransportManager {
-    private static final String TAG = "CompanionTransportManager";
+    private static final String TAG = "CDM_CompanionTransportManager";
     // TODO: flip to false
     private static final boolean DEBUG = true;
 
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 593a63c..fc628cf 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -250,7 +250,9 @@
         // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
         // aware that the virtual display has a secure window on top.
         if ((windowFlags & FLAG_SECURE) != 0) {
-            mSecureWindowCallback.onSecureWindowShown(mDisplayId, activityInfo.applicationInfo.uid);
+            // Post callback on the main thread, so it doesn't block activity launching.
+            mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(mDisplayId,
+                    activityInfo.applicationInfo.uid));
         }
 
         if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index bd1ecb2..9f3f761 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -48,8 +48,7 @@
 import com.android.server.pm.PackageList;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.dex.DynamicCodeLogger;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
@@ -578,6 +577,14 @@
             int filterCallingUid);
 
     /**
+     * Resolves an exported activity intent, allowing instant apps to be resolved.
+     */
+    public abstract ResolveInfo resolveIntentExported(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags,
+            @PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart,
+            int filterCallingUid);
+
+    /**
     * Resolves a service intent, allowing instant apps to be resolved.
     */
     public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
@@ -644,7 +651,7 @@
      * Returns the {@link SystemApi} variant of a package for use with mainline.
      */
     @Nullable
-    public abstract AndroidPackageApi getAndroidPackage(@NonNull String packageName);
+    public abstract AndroidPackage getAndroidPackage(@NonNull String packageName);
 
     @Nullable
     public abstract PackageStateInternal getPackageStateInternal(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index b33d84c..c713a41 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -314,6 +314,14 @@
     private static final DropboxRateLimiter sDropboxRateLimiter = new DropboxRateLimiter();
 
     /**
+     * Reset the dropbox rate limiter.
+     */
+    @VisibleForTesting
+    public static void resetDropboxRateLimiter() {
+        sDropboxRateLimiter.reset();
+    }
+
+    /**
      * Add a tombstone to the DropBox.
      *
      * @param ctx Context
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index e21a3d7..6b3f5e2 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -98,12 +98,17 @@
     }
 
     private String getCallingPackageName() {
-        final String[] packages = mContext.getPackageManager().getPackagesForUid(
-                Binder.getCallingUid());
+        final PackageManager pm = mContext.getPackageManager();
+        final int uid = Binder.getCallingUid();
+        final String[] packages = pm.getPackagesForUid(uid);
         if (packages != null && packages.length > 0) {
            return packages[0];
         }
-        return "unknown";
+        final String name = pm.getNameForUid(uid);
+        if (name != null) {
+            return name;
+        }
+        return String.valueOf(uid);
     }
 
     private void dumpTempValues(String pkg, PrintWriter pw, int type,
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index c375c73..a1adc6f4 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -35,7 +35,6 @@
 
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.pm.Computer;
-import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 
 import java.io.PrintWriter;
@@ -566,7 +565,7 @@
      * "stopped", that is whether it should not be included in the result
      * if the intent requests to excluded stopped objects.
      */
-    protected boolean isFilterStopped(PackageStateInternal packageState, @UserIdInt int userId) {
+    protected boolean isFilterStopped(@NonNull Computer computer, F filter, @UserIdInt int userId) {
         return false;
     }
 
@@ -805,8 +804,7 @@
             int match;
             if (debug) Slog.v(TAG, "Matching against filter " + filter);
 
-            if (excludingStopped && isFilterStopped(computer.getPackageStateInternal(packageName),
-                    userId)) {
+            if (excludingStopped && isFilterStopped(computer, filter, userId)) {
                 if (debug) {
                     Slog.v(TAG, "  Filter's target is stopped; skipping");
                 }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 5393b2a..a6e5aa4 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -314,10 +314,8 @@
             } else {
                 prefix =  "Blocked in monitor " + mCurrentMonitor.getClass().getName();
             }
-            Thread thread = getThread();
-            String threadIdentifier = thread.getName() + ", tid=" + thread.getId();
             long latencySeconds = (SystemClock.uptimeMillis() - mStartTimeMillis) / 1000;
-            return prefix + " on " + mName + " (" + threadIdentifier + ")"
+            return prefix + " on " + mName + " (" + getThread().getName() + ")"
                 + " for " + latencySeconds + "s";
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ccf782a..1b68aba 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -215,6 +215,7 @@
 import android.appwidget.AppWidgetManagerInternal;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledAfter;
 import android.content.AttributionSource;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
@@ -377,6 +378,7 @@
 import com.android.internal.util.function.TriFunction;
 import com.android.internal.util.function.UndecFunction;
 import com.android.server.AlarmManagerInternal;
+import com.android.server.BootReceiver;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.DisplayThread;
 import com.android.server.IntentResolver;
@@ -406,8 +408,8 @@
 import com.android.server.pm.Computer;
 import com.android.server.pm.Installer;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
@@ -584,6 +586,17 @@
     private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
 
     /**
+     * Apps targeting Android U and above will need to export components in order to invoke them
+     * through implicit intents.
+     *
+     * If a component is not exported and invoked, it will be removed from the list of receivers.
+     * This applies specifically to activities and broadcasts.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    public static final long IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS = 229362273;
+
+    /**
      * The maximum number of bytes that {@link #setProcessStateSummary} accepts.
      *
      * @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])}
@@ -12378,6 +12391,58 @@
     }
 
     /**
+     * Filters out non-exported components in a given list of broadcast filters
+     * @param intent the original intent
+     * @param callingUid the calling UID
+     * @param query the list of broadcast filters
+     * @param platformCompat the instance of platform compat
+     */
+    private static void filterNonExportedComponents(Intent intent, int callingUid,
+            List query, PlatformCompat platformCompat, String callerPackage) {
+        if (query == null
+                || intent.getPackage() != null
+                || intent.getComponent() != null
+                || ActivityManager.canAccessUnexportedComponents(callingUid)) {
+            return;
+        }
+        for (int i = query.size() - 1; i >= 0; i--) {
+            String componentInfo;
+            ResolveInfo resolveInfo;
+            BroadcastFilter broadcastFilter;
+            if (query.get(i) instanceof ResolveInfo) {
+                resolveInfo = (ResolveInfo) query.get(i);
+                if (resolveInfo.getComponentInfo().exported) {
+                    continue;
+                }
+                componentInfo = resolveInfo.getComponentInfo()
+                        .getComponentName().flattenToShortString();
+            } else if (query.get(i) instanceof BroadcastFilter) {
+                broadcastFilter = (BroadcastFilter) query.get(i);
+                if (broadcastFilter.exported) {
+                    continue;
+                }
+                componentInfo = broadcastFilter.packageName;
+            } else {
+                continue;
+            }
+            if (!platformCompat.isChangeEnabledByUid(
+                    IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, callingUid)) {
+                Slog.w(TAG, "Non-exported component not filtered out "
+                        + "(will be filtered out once the app targets U+)- intent: "
+                        + intent.getAction() + ", component: "
+                        + componentInfo + ", sender: "
+                        + callerPackage);
+                return;
+            }
+            Slog.w(TAG, "Non-exported component filtered out - intent: "
+                    + intent.getAction() + ", component: "
+                    + componentInfo + ", sender: "
+                    + callerPackage);
+            query.remove(i);
+        }
+    }
+
+    /**
      * Main code for cleaning up a process when it has gone away.  This is
      * called both as a result of the process dying, or directly when stopping
      * a process when running in single process mode.
@@ -14216,6 +14281,8 @@
             }
         }
 
+        filterNonExportedComponents(intent, callingUid, registeredReceivers,
+                mPlatformCompat, callerPackage);
         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
         if (!ordered && NR > 0) {
             // If we are not serializing this broadcast, then send the
@@ -14318,6 +14385,8 @@
         if ((receivers != null && receivers.size() > 0)
                 || resultTo != null) {
             BroadcastQueue queue = broadcastQueueForIntent(intent);
+            filterNonExportedComponents(intent, callingUid, receivers,
+                    mPlatformCompat, callerPackage);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                     callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                     requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
@@ -16144,8 +16213,7 @@
     @Override
     public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) {
         // Permission check done inside UserController.
-        return mUserController.startUserOnSecondaryDisplay(userId, displayId,
-                /* unlockListener= */ null);
+        return mUserController.startUserOnSecondaryDisplay(userId, displayId);
     }
 
     /**
@@ -16396,11 +16464,6 @@
         }
     }
 
-    @Override
-    public void enableBinderTracing() {
-        Binder.enableTracingForUid(Binder.getCallingUid());
-    }
-
     @VisibleForTesting
     public final class LocalService extends ActivityManagerInternal
             implements ActivityManagerLocal {
@@ -17812,6 +17875,10 @@
         for (BroadcastQueue queue : mBroadcastQueues) {
             queue.waitForIdle(pw);
         }
+        if (pw != null) {
+            pw.println("All broadcast queues are idle!");
+            pw.flush();
+        }
     }
 
     public void waitForBroadcastBarrier(@Nullable PrintWriter pw) {
@@ -17878,10 +17945,11 @@
     }
 
     /**
-     * Reset the dropbox rate limiter
+     * Reset the dropbox rate limiter here and in BootReceiver
      */
     void resetDropboxRateLimiter() {
         mDropboxRateLimiter.reset();
+        BootReceiver.resetDropboxRateLimiter();
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index cc2b693..a41a311 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -44,6 +44,7 @@
 import android.net.INetworkManagementEventObserver;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.os.BatteryConsumer;
 import android.os.BatteryManagerInternal;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
@@ -2292,6 +2293,10 @@
         pw.println("  --settings: dump the settings key/values related to batterystats");
         pw.println("  --cpu: dump cpu stats for debugging purpose");
         pw.println("  --power-profile: dump the power profile constants");
+        pw.println("  --usage: write battery usage stats. Optional arguments:");
+        pw.println("     --proto: output as a binary protobuffer");
+        pw.println("     --model power-profile: use the power profile model"
+                + " even if measured energy is available");
         pw.println("  <package.name>: optional name of package to filter output by.");
         pw.println("  -h: print this help text.");
         pw.println("Battery stats (batterystats) commands:");
@@ -2335,6 +2340,31 @@
         }
     }
 
+    private void dumpUsageStatsToProto(FileDescriptor fd, PrintWriter pw, int model,
+            boolean proto) {
+        awaitCompletion();
+        syncStats("dump", BatteryExternalStatsWorker.UPDATE_ALL);
+
+        BatteryUsageStatsQuery.Builder builder = new BatteryUsageStatsQuery.Builder()
+                .setMaxStatsAgeMs(0)
+                .includeProcessStateData()
+                .includePowerModels();
+        if (model == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+            builder.powerProfileModeledOnly();
+        }
+        BatteryUsageStatsQuery query = builder.build();
+        synchronized (mStats) {
+            mStats.prepareForDumpLocked();
+            BatteryUsageStats batteryUsageStats =
+                    mBatteryUsageStatsProvider.getBatteryUsageStats(query);
+            if (proto) {
+                batteryUsageStats.dumpToProto(fd);
+            } else {
+                batteryUsageStats.dump(pw, "");
+            }
+        }
+    }
+
     private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
         i++;
         if (i >= args.length) {
@@ -2488,6 +2518,35 @@
                 } else if ("--power-profile".equals(arg)) {
                     dumpPowerProfile(pw);
                     return;
+                } else if ("--usage".equals(arg)) {
+                    int model = BatteryConsumer.POWER_MODEL_UNDEFINED;
+                    boolean proto = false;
+                    for (int j = i + 1; j < args.length; j++) {
+                        switch (args[j]) {
+                            case "--proto":
+                                proto = true;
+                                break;
+                            case "--model": {
+                                if (j + 1 < args.length) {
+                                    j++;
+                                    if ("power-profile".equals(args[j])) {
+                                        model = BatteryConsumer.POWER_MODEL_POWER_PROFILE;
+                                    } else {
+                                        pw.println("Unknown power model: " + args[j]);
+                                        dumpHelp(pw);
+                                        return;
+                                    }
+                                } else {
+                                    pw.println("--model without a value");
+                                    dumpHelp(pw);
+                                    return;
+                                }
+                                break;
+                            }
+                        }
+                    }
+                    dumpUsageStatsToProto(fd, pw, model, proto);
+                    return;
                 } else if ("-a".equals(arg)) {
                     flags |= BatteryStats.DUMP_VERBOSE;
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index a36c298..86c9770 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -81,7 +81,7 @@
 import com.android.server.LocalServices;
 import com.android.server.RescueParty;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index 6087f76..e5975c3 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -108,7 +108,7 @@
     }
 
     /** Resets the rate limiter memory. */
-    void reset() {
+    public void reset() {
         synchronized (mErrorClusterRecords) {
             mErrorClusterRecords.clear();
         }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 80dd266..dbe80c8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2534,7 +2534,7 @@
             capability |= capabilityFromFGS;
         }
 
-        capability |= getDefaultCapability(psr, procState);
+        capability |= getDefaultCapability(app, procState);
 
         // Do final modification to adj.  Everything we do between here and applying
         // the final setAdj must be done in this function, because we will also use
@@ -2556,7 +2556,7 @@
                 || state.getCurCapability() != prevCapability;
     }
 
-    private int getDefaultCapability(ProcessServiceRecord psr, int procState) {
+    private int getDefaultCapability(ProcessRecord app, int procState) {
         switch (procState) {
             case PROCESS_STATE_PERSISTENT:
             case PROCESS_STATE_PERSISTENT_UI:
@@ -2565,15 +2565,13 @@
             case PROCESS_STATE_BOUND_TOP:
                 return PROCESS_CAPABILITY_NETWORK;
             case PROCESS_STATE_FOREGROUND_SERVICE:
-                if (psr.hasForegroundServices()) {
-                    // Capability from FGS are conditional depending on foreground service type in
-                    // manifest file and the mAllowWhileInUsePermissionInFgs flag.
-                    return PROCESS_CAPABILITY_NETWORK;
+                if (app.getActiveInstrumentation() != null) {
+                    return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK ;
                 } else {
-                    // process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
-                    // the implicit capability could be removed in the future, client should use
-                    // BIND_INCLUDE_CAPABILITY flag.
-                    return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK;
+                    // Capability from foreground service is conditional depending on
+                    // foregroundServiceType in the manifest file and the
+                    // mAllowWhileInUsePermissionInFgs flag.
+                    return PROCESS_CAPABILITY_NETWORK;
                 }
             case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
                 return PROCESS_CAPABILITY_NETWORK;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index affb084..992d416 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -133,7 +133,7 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ProcessChangeItem;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.wm.ActivityServiceConnectionsHolder;
 import com.android.server.wm.WindowManagerService;
@@ -2200,16 +2200,25 @@
             Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
             boolean bindMountAppStorageDirs = false;
             boolean bindMountAppsData = mAppDataIsolationEnabled
-                    && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
+                    && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid)
+                        || app.isSdkSandbox)
                     && mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
 
             // Get all packages belongs to the same shared uid. sharedPackages is empty array
             // if it doesn't have shared uid.
             final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
-            final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
-                    app.info.packageName, app.userId);
-            final String[] targetPackagesList = sharedPackages.length == 0
-                    ? new String[]{app.info.packageName} : sharedPackages;
+
+            // In the case of sdk sandbox, the pkgDataInfoMap of only the client app associated with
+            // the sandbox is required to handle app visibility restrictions for the sandbox.
+            final String[] targetPackagesList;
+            if (app.isSdkSandbox) {
+                targetPackagesList = new String[]{app.sdkSandboxClientAppPackage};
+            } else {
+                final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
+                        app.info.packageName, app.userId);
+                targetPackagesList = sharedPackages.length == 0
+                        ? new String[]{app.info.packageName} : sharedPackages;
+            }
 
             final boolean hasAppStorage = hasAppStorage(pmInt, app.info.packageName);
 
@@ -2235,7 +2244,7 @@
                 bindMountAppsData = false;
             }
 
-            if (!hasAppStorage) {
+            if (!hasAppStorage && !app.isSdkSandbox) {
                 bindMountAppsData = false;
                 pkgDataInfoMap = null;
                 allowlistedAppDataInfoMap = null;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 043da55..6775c99 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -376,6 +376,11 @@
     private boolean mDelayUserDataLocking;
 
     /**
+     * Users are only allowed to be unlocked after boot complete.
+     */
+    private volatile boolean mAllowUserUnlocking;
+
+    /**
      * Keep track of last active users for mDelayUserDataLocking.
      * The latest stopped user is placed in front while the least recently stopped user in back.
      */
@@ -434,6 +439,11 @@
         mUserLru.add(UserHandle.USER_SYSTEM);
         mLockPatternUtils = mInjector.getLockPatternUtils();
         updateStartedUserArrayLU();
+
+        // TODO(b/232452368): currently mAllowUserUnlocking is only used on devices with HSUM
+        // (Headless System User Mode), but on master it will be used by all devices (and hence this
+        // initial assignment should be removed).
+        mAllowUserUnlocking = !UserManager.isHeadlessSystemUserMode();
     }
 
     void setInitialConfig(boolean userSwitchUiEnabled, int maxRunningUsers,
@@ -1375,8 +1385,9 @@
         }
         final int profilesToStartSize = profilesToStart.size();
         int i = 0;
-        // TODO(b/239982558): pass displayId
         for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) {
+            // NOTE: this method is setting the profiles of the current user - which is always
+            // assigned to the default display - so there's no need to pass PARENT_DISPLAY
             startUser(profilesToStart.get(i).id, /* foreground= */ false);
         }
         if (i < profilesToStartSize) {
@@ -1419,8 +1430,10 @@
             return false;
         }
 
-        // TODO(b/239982558): pass proper displayId
-        return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, /* foreground= */ false,
+        int displayId = mInjector.isUsersOnSecondaryDisplaysEnabled()
+                ? UserManagerInternal.PARENT_DISPLAY
+                : Display.DEFAULT_DISPLAY;
+        return startUserNoChecks(userId, displayId, /* foreground= */ false,
                 /* unlockListener= */ null);
     }
 
@@ -1472,8 +1485,7 @@
 
     // TODO(b/239982558): add javadoc (need to wait until the intents / SystemService callbacks are
     // defined
-    boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId,
-            @Nullable IProgressListener unlockListener) {
+    boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId) {
         checkCallingHasOneOfThosePermissions("startUserOnSecondaryDisplay",
                 MANAGE_USERS, CREATE_USERS);
 
@@ -1482,7 +1494,8 @@
                 "Cannot use DEFAULT_DISPLAY");
 
         try {
-            return startUserNoChecks(userId, displayId, /* foreground= */ false, unlockListener);
+            return startUserNoChecks(userId, displayId, /* foreground= */ false,
+                    /* unlockListener= */ null);
         } catch (RuntimeException e) {
             Slogf.w(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
             return false;
@@ -1514,8 +1527,6 @@
             Preconditions.checkArgument(!foreground, "Cannot start user %d in foreground AND "
                     + "on secondary display (%d)", userId, displayId);
         }
-        mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId);
-
         // TODO(b/239982558): log display id (or use a new event)
         EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId);
 
@@ -1571,6 +1582,8 @@
                 return false;
             }
 
+            mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId);
+
             // TODO(b/239982558): might need something similar for bg users on secondary display
             if (foreground && isUserSwitchUiEnabled()) {
                 t.traceBegin("startFreezingScreen");
@@ -1798,6 +1811,22 @@
 
     private boolean unlockUserCleared(final @UserIdInt int userId, byte[] secret,
             IProgressListener listener) {
+        // Delay user unlocking for headless system user mode until the system boot
+        // completes. When the system boot completes, the {@link #onBootCompleted()}
+        // method unlocks all started users for headless system user mode. This is done
+        // to prevent unlocking the users too early during the system boot up.
+        // Otherwise, emulated volumes are mounted too early during the system
+        // boot up. When vold is reset on boot complete, vold kills all apps/services
+        // (that use these emulated volumes) before unmounting the volumes(b/241929666).
+        // In the past, these killings have caused the system to become too unstable on
+        // some occasions.
+        // Any unlocks that get delayed by this will be done by onBootComplete() instead.
+        if (!mAllowUserUnlocking) {
+            Slogf.i(TAG, "Not unlocking user %d yet because boot hasn't completed", userId);
+            notifyFinished(userId, listener);
+            return false;
+        }
+
         UserState uss;
         if (!StorageManager.isUserKeyUnlocked(userId)) {
             final UserInfo userInfo = getUserInfo(userId);
@@ -2394,7 +2423,44 @@
         }
     }
 
+    @VisibleForTesting
+    void setAllowUserUnlocking(boolean allowed) {
+        mAllowUserUnlocking = allowed;
+        if (DEBUG_MU) {
+            // TODO(b/245335748): use Slogf.d instead
+            // Slogf.d(TAG, new Exception(), "setAllowUserUnlocking(%b)", allowed);
+            android.util.Slog.d(TAG, "setAllowUserUnlocking():" + allowed, new Exception());
+        }
+    }
+
+    /**
+     * @deprecated TODO(b/232452368): this logic will be merged into sendBootCompleted
+     */
+    @Deprecated
+    private void onBootCompletedOnHeadlessSystemUserModeDevices() {
+        setAllowUserUnlocking(true);
+
+        // Get a copy of mStartedUsers to use outside of lock.
+        SparseArray<UserState> startedUsers;
+        synchronized (mLock) {
+            startedUsers = mStartedUsers.clone();
+        }
+        // USER_SYSTEM must be processed first.  It will be first in the array, as its ID is lowest.
+        Preconditions.checkArgument(startedUsers.keyAt(0) == UserHandle.USER_SYSTEM);
+        for (int i = 0; i < startedUsers.size(); i++) {
+            UserState uss = startedUsers.valueAt(i);
+            int userId = uss.mHandle.getIdentifier();
+            Slogf.i(TAG, "Attempting to unlock user %d on boot complete", userId);
+            maybeUnlockUser(userId);
+        }
+    }
+
     void sendBootCompleted(IIntentReceiver resultTo) {
+        if (UserManager.isHeadlessSystemUserMode()) {
+            // Unlocking users is delayed until boot complete for headless system user mode.
+            onBootCompletedOnHeadlessSystemUserModeDevices();
+        }
+
         // Get a copy of mStartedUsers to use outside of lock
         SparseArray<UserState> startedUsers;
         synchronized (mLock) {
@@ -2845,6 +2911,7 @@
             pw.println("  mTargetUserId:" + mTargetUserId);
             pw.println("  mLastActiveUsers:" + mLastActiveUsers);
             pw.println("  mDelayUserDataLocking:" + mDelayUserDataLocking);
+            pw.println("  mAllowUserUnlocking:" + mAllowUserUnlocking);
             pw.println("  shouldStopUserOnSwitch():" + shouldStopUserOnSwitch());
             pw.println("  mStopUserOnSwitch:" + mStopUserOnSwitch);
             pw.println("  mMaxRunningUsers:" + mMaxRunningUsers);
@@ -3484,5 +3551,9 @@
                 }
             }, reason);
         }
+
+        boolean isUsersOnSecondaryDisplaysEnabled() {
+            return UserManager.isUsersOnSecondaryDisplaysEnabled();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 71a5511..4741849 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -35,18 +35,20 @@
 public final class UserState {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "UserState" : TAG_AM;
 
+    // user doesn't exist.
+    public static final int STATE_NONE = -1;
     // User is first coming up.
-    public final static int STATE_BOOTING = 0;
+    public static final int STATE_BOOTING = 0;
     // User is in the locked state.
-    public final static int STATE_RUNNING_LOCKED = 1;
+    public static final int STATE_RUNNING_LOCKED = 1;
     // User is in the unlocking state.
-    public final static int STATE_RUNNING_UNLOCKING = 2;
+    public static final int STATE_RUNNING_UNLOCKING = 2;
     // User is in the running state.
-    public final static int STATE_RUNNING_UNLOCKED = 3;
+    public static final int STATE_RUNNING_UNLOCKED = 3;
     // User is in the initial process of being stopped.
-    public final static int STATE_STOPPING = 4;
+    public static final int STATE_STOPPING = 4;
     // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
-    public final static int STATE_SHUTDOWN = 5;
+    public static final int STATE_SHUTDOWN = 5;
 
     public final UserHandle mHandle;
     public final ArrayList<IStopUserCallback> mStopCallbacks = new ArrayList<>();
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 0f5aa3a..4aaf1ab 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -52,6 +52,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost.SurfacePackage;
 import android.view.WindowManager;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -843,8 +844,8 @@
         final SurfaceControl overlaySurfaceControl =
                 overlaySurfacePackage != null ? overlaySurfacePackage.getSurfaceControl() : null;
         mBackgroundExecutor.execute(() -> {
-            final SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder =
-                    new SurfaceControl.LayerCaptureArgs.Builder(/* layer */ null);
+            final ScreenCapture.LayerCaptureArgs.Builder layerCaptureArgsBuilder =
+                    new ScreenCapture.LayerCaptureArgs.Builder(/* layer */ null);
             if (overlaySurfaceControl != null) {
                 SurfaceControl[] excludeLayers = new SurfaceControl[1];
                 excludeLayers[0] = overlaySurfaceControl;
diff --git a/services/core/java/com/android/server/app/TEST_MAPPING b/services/core/java/com/android/server/app/TEST_MAPPING
new file mode 100644
index 0000000..0ba4d8c
--- /dev/null
+++ b/services/core/java/com/android/server/app/TEST_MAPPING
@@ -0,0 +1,23 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsGameManagerTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.app"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7bdcfdb..4a7e631 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -16,9 +16,6 @@
 
 package com.android.server.appop;
 
-import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
-import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
 import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED;
 import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
@@ -46,6 +43,7 @@
 import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
+import static android.app.AppOpsManager.OP_VIBRATE;
 import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
 import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED;
 import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
@@ -56,13 +54,6 @@
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS;
 import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
-import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
-import static android.app.AppOpsManager.UID_STATE_CACHED;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
-import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
-import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
-import static android.app.AppOpsManager.UID_STATE_TOP;
 import static android.app.AppOpsManager._NUM_OP;
 import static android.app.AppOpsManager.extractFlagsFromKey;
 import static android.app.AppOpsManager.extractUidStateFromKey;
@@ -72,7 +63,6 @@
 import static android.app.AppOpsManager.opRestrictsRead;
 import static android.app.AppOpsManager.opToName;
 import static android.app.AppOpsManager.opToPublicName;
-import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
 import static android.content.Intent.EXTRA_REPLACING;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
@@ -80,8 +70,6 @@
 
 import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
 
-import static java.lang.Long.max;
-
 import android.Manifest;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -167,6 +155,7 @@
 import com.android.internal.app.IAppOpsStartedCallback;
 import com.android.internal.app.MessageSamplingConfig;
 import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.os.Clock;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
@@ -177,7 +166,7 @@
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemServiceManager;
 import com.android.server.pm.PackageList;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedAttribution;
 import com.android.server.policy.AppOpsPolicy;
 
@@ -236,39 +225,11 @@
     // Constant meaning that any UID should be matched when dispatching callbacks
     private static final int UID_ANY = -2;
 
-    // Map from process states to the uid states we track.
-    private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
-        UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT
-        UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT_UI
-        UID_STATE_TOP,                  // ActivityManager.PROCESS_STATE_TOP
-        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_TOP
-        UID_STATE_FOREGROUND_SERVICE,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
-        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_BACKUP
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_SERVICE
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_RECEIVER
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_TOP_SLEEPING
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HOME
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_RECENT
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_EMPTY
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
-    };
-
     private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
             OP_PLAY_AUDIO,
             OP_RECORD_AUDIO,
             OP_CAMERA,
-    };
-
-    private static final int[] WATCHABLE_NON_PERMISSION_OPS = {
-            OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+            OP_VIBRATE,
     };
 
     private static final int MAX_UNFORWARDED_OPS = 10;
@@ -346,8 +307,6 @@
 
     volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
 
-    long mLastRealtime;
-
     /*
      * These are app op restrictions imposed per user from various parties.
      */
@@ -408,6 +367,21 @@
     /** Interface for app-op modes.*/
     @VisibleForTesting AppOpsServiceInterface mAppOpsServiceInterface;
 
+    private AppOpsUidStateTracker mUidStateTracker;
+
+    /** Hands the definition of foreground and uid states */
+    @GuardedBy("this")
+    public AppOpsUidStateTracker getUidStateTracker() {
+        if (mUidStateTracker == null) {
+            mUidStateTracker = new AppOpsUidStateTrackerImpl(
+                    LocalServices.getService(ActivityManagerInternal.class), mHandler,
+                    Clock.SYSTEM_CLOCK, mConstants);
+
+            mUidStateTracker.addUidStateChangedCallback(mHandler, this::onUidStateChanged);
+        }
+        return mUidStateTracker;
+    }
+
     /**
      * An unsynchronized pool of {@link OpEventProxyInfo} objects.
      */
@@ -467,7 +441,6 @@
      * global Settings. Any access to this class or its fields should be done while
      * holding the AppOpsService lock.
      */
-    @VisibleForTesting
     final class Constants extends ContentObserver {
 
         /**
@@ -555,14 +528,6 @@
     final class UidState {
         public final int uid;
 
-        public int state = UID_STATE_CACHED;
-        public int pendingState = UID_STATE_CACHED;
-        public long pendingStateCommitTime;
-        public int capability;
-        public int pendingCapability;
-        public boolean appWidgetVisible;
-        public boolean pendingAppWidgetVisible;
-
         public ArrayMap<String, Ops> pkgOps;
 
         // true indicates there is an interested observer, false there isn't but it has such an op
@@ -596,10 +561,8 @@
                 }
             }
             return (pkgOps == null || pkgOps.isEmpty())
-                    && (state == UID_STATE_CACHED
-                    && (pendingState == UID_STATE_CACHED))
-                    && (mAppOpsServiceInterface.areUidModesDefault(uid)
-                    && areAllPackageModesDefault);
+                    && mAppOpsServiceInterface.areUidModesDefault(uid)
+                    && areAllPackageModesDefault;
         }
 
         // Functions for uid mode access and manipulation.
@@ -615,52 +578,9 @@
             return mAppOpsServiceInterface.setUidMode(uid, op, mode);
         }
 
+        @SuppressWarnings("GuardedBy")
         int evalMode(int op, int mode) {
-            if (mode == MODE_FOREGROUND) {
-                if (appWidgetVisible) {
-                    return MODE_ALLOWED;
-                } else if (mActivityManagerInternal != null
-                        && mActivityManagerInternal.isPendingTopUid(uid)) {
-                    return MODE_ALLOWED;
-                } else if (mActivityManagerInternal != null
-                        && mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
-                    return MODE_ALLOWED;
-                } else if (state <= UID_STATE_TOP) {
-                    // process is in TOP.
-                    return MODE_ALLOWED;
-                } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
-                    // process is in foreground, check its capability.
-                    switch (op) {
-                        case AppOpsManager.OP_FINE_LOCATION:
-                        case AppOpsManager.OP_COARSE_LOCATION:
-                        case AppOpsManager.OP_MONITOR_LOCATION:
-                        case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
-                            if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
-                                return MODE_ALLOWED;
-                            } else {
-                                return MODE_IGNORED;
-                            }
-                        case OP_CAMERA:
-                            if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
-                                return MODE_ALLOWED;
-                            } else {
-                                return MODE_IGNORED;
-                            }
-                        case OP_RECORD_AUDIO:
-                            if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
-                                return MODE_ALLOWED;
-                            } else {
-                                return MODE_IGNORED;
-                            }
-                        default:
-                            return MODE_ALLOWED;
-                    }
-                } else {
-                    // process is not in foreground.
-                    return MODE_IGNORED;
-                }
-            }
-            return mode;
+            return getUidStateTracker().evalMode(uid, op, mode);
         }
 
         public void evalForegroundOps() {
@@ -683,6 +603,16 @@
                 }
             }
         }
+
+        @SuppressWarnings("GuardedBy")
+        public int getState() {
+            return getUidStateTracker().getUidState(uid);
+        }
+
+        @SuppressWarnings("GuardedBy")
+        public void dump(PrintWriter pw, long nowElapsed) {
+            getUidStateTracker().dumpUidState(pw, uid, nowElapsed);
+        }
     }
 
     final static class Ops extends SparseArray<Op> {
@@ -710,7 +640,7 @@
         }
     }
 
-    /** Returned from {@link #verifyAndGetBypass(int, String, String, String, boolean)}. */
+    /** Returned from {@link #verifyAndGetBypass(int, String, String, String)}. */
     private static final class PackageVerificationResult {
 
         final RestrictionBypass bypass;
@@ -1481,10 +1411,6 @@
                     UserHandle.getUserId(this.uid));
         }
 
-        int evalMode() {
-            return uidState.evalMode(op, getMode());
-        }
-
         void removeAttributionsWithNoTime() {
             for (int i = mAttributions.size() - 1; i >= 0; i--) {
                 if (!mAttributions.valueAt(i).hasAnyTime()) {
@@ -2096,79 +2022,88 @@
         }
     }
 
-    /**
-     * Update the pending state for the uid
-     *
-     * @param currentTime The current elapsed real time
-     * @param uid The uid that has a pending state
-     */
-    private void updatePendingState(long currentTime, int uid) {
+    // The callback method from ForegroundPolicyInterface
+    private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) {
         synchronized (this) {
-            mLastRealtime = max(currentTime, mLastRealtime);
-            updatePendingStateIfNeededLocked(mUidStates.get(uid));
-        }
-    }
+            UidState uidState = getUidStateLocked(uid, true);
 
-    public void updateUidProcState(int uid, int procState,
-            @ActivityManager.ProcessCapability int capability) {
-        synchronized (this) {
-            final UidState uidState = getUidStateLocked(uid, true);
-            final int newState = PROCESS_STATE_TO_UID_STATE[procState];
-            if (uidState != null && (uidState.pendingState != newState
-                    || uidState.pendingCapability != capability)) {
-                final int oldPendingState = uidState.pendingState;
-                uidState.pendingState = newState;
-                uidState.pendingCapability = capability;
-                if (newState < uidState.state
-                        || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
-                                && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
-                    // We are moving to a more important state, or the new state may be in the
-                    // foreground and the old state is in the background, then always do it
-                    // immediately.
-                    commitUidPendingStateLocked(uidState);
-                } else if (newState == uidState.state && capability != uidState.capability) {
-                    // No change on process state, but process capability has changed.
-                    commitUidPendingStateLocked(uidState);
-                } else if (uidState.pendingStateCommitTime == 0) {
-                    // We are moving to a less important state for the first time,
-                    // delay the application for a bit.
-                    final long settleTime;
-                    if (uidState.state <= UID_STATE_TOP) {
-                        settleTime = mConstants.TOP_STATE_SETTLE_TIME;
-                    } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
-                        settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
-                    } else {
-                        settleTime = mConstants.BG_STATE_SETTLE_TIME;
+            if (uidState != null && foregroundModeMayChange && uidState.hasForegroundWatchers) {
+                for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
+                    if (!uidState.foregroundOps.valueAt(fgi)) {
+                        continue;
                     }
-                    final long commitTime = SystemClock.elapsedRealtime() + settleTime;
-                    uidState.pendingStateCommitTime = commitTime;
+                    final int code = uidState.foregroundOps.keyAt(fgi);
 
-                    mHandler.sendMessageDelayed(
-                            PooledLambda.obtainMessage(AppOpsService::updatePendingState, this,
-                                    commitTime + 1, uid), settleTime + 1);
-                }
-
-                if (uidState.pkgOps != null) {
-                    int numPkgs = uidState.pkgOps.size();
-                    for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
-                        Ops ops = uidState.pkgOps.valueAt(pkgNum);
-
-                        int numOps = ops.size();
-                        for (int opNum = 0; opNum < numOps; opNum++) {
-                            Op op = ops.valueAt(opNum);
-
-                            int numAttributions = op.mAttributions.size();
-                            for (int attributionNum = 0; attributionNum < numAttributions;
-                                    attributionNum++) {
-                                AttributedOp attributedOp = op.mAttributions.valueAt(
-                                        attributionNum);
-
-                                attributedOp.onUidStateChanged(newState);
+                    if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)
+                            && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) {
+                        mHandler.sendMessage(PooledLambda.obtainMessage(
+                                AppOpsService::notifyOpChangedForAllPkgsInUid,
+                                this, code, uidState.uid, true, null));
+                    } else if (uidState.pkgOps != null) {
+                        final ArraySet<OnOpModeChangedListener> listenerSet =
+                                mAppOpsServiceInterface.getOpModeChangedListeners(code);
+                        if (listenerSet != null) {
+                            for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) {
+                                final OnOpModeChangedListener listener = listenerSet.valueAt(cbi);
+                                if ((listener.getFlags()
+                                        & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+                                        || !listener.isWatchingUid(uidState.uid)) {
+                                    continue;
+                                }
+                                for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
+                                    final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
+                                    if (op == null) {
+                                        continue;
+                                    }
+                                    if (op.getMode() == AppOpsManager.MODE_FOREGROUND) {
+                                        mHandler.sendMessage(PooledLambda.obtainMessage(
+                                                AppOpsService::notifyOpChanged,
+                                                this, listenerSet.valueAt(cbi), code, uidState.uid,
+                                                uidState.pkgOps.keyAt(pkgi)));
+                                    }
+                                }
                             }
                         }
                     }
                 }
             }
+
+            if (uidState != null && uidState.pkgOps != null) {
+                int numPkgs = uidState.pkgOps.size();
+                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+                    Ops ops = uidState.pkgOps.valueAt(pkgNum);
+
+                    int numOps = ops.size();
+                    for (int opNum = 0; opNum < numOps; opNum++) {
+                        Op op = ops.valueAt(opNum);
+
+                        int numAttributions = op.mAttributions.size();
+                        for (int attributionNum = 0; attributionNum < numAttributions;
+                                attributionNum++) {
+                            AttributedOp attributedOp = op.mAttributions.valueAt(
+                                    attributionNum);
+
+                            attributedOp.onUidStateChanged(state);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Notify the proc state or capability has changed for a certain UID.
+     */
+    public void updateUidProcState(int uid, int procState,
+            @ActivityManager.ProcessCapability int capability) {
+        synchronized (this) {
+            getUidStateTracker().updateUidProcState(uid, procState, capability);
+            if (!mUidStates.contains(uid)) {
+                UidState uidState = new UidState(uid);
+                mUidStates.put(uid, uidState);
+                onUidStateChanged(uid,
+                        AppOpsUidStateTracker.processStateToUidState(procState), false);
+            }
         }
     }
 
@@ -3162,7 +3097,7 @@
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
-            return raw ? op.getMode() : op.evalMode();
+            return raw ? op.getMode() : op.uidState.evalMode(op.op, op.getMode());
         }
     }
 
@@ -3380,7 +3315,7 @@
             final int switchCode = AppOpsManager.opToSwitch(code);
             final UidState uidState = ops.uidState;
             if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, false)) {
-                attributedOp.rejected(uidState.state, flags);
+                attributedOp.rejected(uidState.getState(), flags);
                 scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
                         AppOpsManager.MODE_IGNORED);
                 return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
@@ -3394,7 +3329,7 @@
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
-                    attributedOp.rejected(uidState.state, flags);
+                    attributedOp.rejected(uidState.getState(), flags);
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
                             uidMode);
                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
@@ -3402,12 +3337,12 @@
             } else {
                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
                         : op;
-                final int mode = switchOp.evalMode();
+                final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
                 if (mode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
-                    attributedOp.rejected(uidState.state, flags);
+                    attributedOp.rejected(uidState.getState(), flags);
                     scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
                             mode);
                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
@@ -3422,7 +3357,8 @@
             }
             scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
                     AppOpsManager.MODE_ALLOWED);
-            attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
+            attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
+                    uidState.getState(),
                     flags);
 
             if (shouldCollectAsyncNotedOp) {
@@ -3913,7 +3849,7 @@
                                 + packageName + " flags: " + AppOpsManager.flagsToString(flags));
                     }
                     if (!dryRun) {
-                        attributedOp.rejected(uidState.state, flags);
+                        attributedOp.rejected(uidState.getState(), flags);
                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
                                 flags, uidMode, startType, attributionFlags, attributionChainId);
                     }
@@ -3922,14 +3858,14 @@
             } else {
                 final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
                         : op;
-                final int mode = switchOp.evalMode();
+                final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
                 if (mode != AppOpsManager.MODE_ALLOWED
                         && (!startIfModeDefault || mode != MODE_DEFAULT)) {
                     if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
                             + packageName + " flags: " + AppOpsManager.flagsToString(flags));
                     if (!dryRun) {
-                        attributedOp.rejected(uidState.state, flags);
+                        attributedOp.rejected(uidState.getState(), flags);
                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
                                 flags, mode, startType, attributionFlags, attributionChainId);
                     }
@@ -3943,12 +3879,12 @@
                 try {
                     if (isRestricted) {
                         attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
-                                proxyAttributionTag, uidState.state, flags, attributionFlags,
-                                attributionChainId);
+                                proxyAttributionTag, uidState.getState(), flags,
+                                attributionFlags, attributionChainId);
                     } else {
                         attributedOp.started(clientId, proxyUid, proxyPackageName,
-                                proxyAttributionTag, uidState.state, flags, attributionFlags,
-                                attributionChainId);
+                                proxyAttributionTag, uidState.getState(), flags,
+                                attributionFlags, attributionChainId);
                         startType = START_TYPE_STARTED;
                     }
                 } catch (RemoteException e) {
@@ -4252,7 +4188,7 @@
     public boolean shouldCollectNotes(int opCode) {
         Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
 
-        if (ArrayUtils.contains(WATCHABLE_NON_PERMISSION_OPS, opCode)) {
+        if (AppOpsManager.shouldForceCollectNoteForOp(opCode)) {
             return true;
         }
 
@@ -4362,101 +4298,14 @@
             }
             uidState = new UidState(uid);
             mUidStates.put(uid, uidState);
-        } else {
-            updatePendingStateIfNeededLocked(uidState);
         }
+
         return uidState;
     }
 
-    /**
-     * Check if the pending state should be updated and do so if needed
-     *
-     * @param uidState The uidState that might have a pending state
-     */
-    private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) {
-        if (uidState != null) {
-            if (uidState.pendingStateCommitTime != 0) {
-                if (uidState.pendingStateCommitTime < mLastRealtime) {
-                    commitUidPendingStateLocked(uidState);
-                } else {
-                    mLastRealtime = SystemClock.elapsedRealtime();
-                    if (uidState.pendingStateCommitTime < mLastRealtime) {
-                        commitUidPendingStateLocked(uidState);
-                    }
-                }
-            }
-        }
-    }
-
-    private void commitUidPendingStateLocked(UidState uidState) {
-        if (uidState.hasForegroundWatchers) {
-            for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
-                if (!uidState.foregroundOps.valueAt(fgi)) {
-                    continue;
-                }
-                final int code = uidState.foregroundOps.keyAt(fgi);
-                // For location ops we consider fg state only if the fg service
-                // is of location type, for all other ops any fg service will do.
-                final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code);
-                final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState;
-                final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState;
-                if (resolvedLastFg == resolvedNowFg
-                        && uidState.capability == uidState.pendingCapability
-                        && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) {
-                    continue;
-                }
-
-                if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)
-                        && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) {
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppOpsService::notifyOpChangedForAllPkgsInUid,
-                            this, code, uidState.uid, true, null));
-                } else if (uidState.pkgOps != null) {
-                    final ArraySet<OnOpModeChangedListener> listenerSet =
-                            mAppOpsServiceInterface.getOpModeChangedListeners(code);
-                    if (listenerSet != null) {
-                        for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) {
-                            final OnOpModeChangedListener listener = listenerSet.valueAt(cbi);
-                            if ((listener.getFlags()
-                                    & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
-                                    || !listener.isWatchingUid(uidState.uid)) {
-                                continue;
-                            }
-                            for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
-                                final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
-                                if (op == null) {
-                                    continue;
-                                }
-                                if (op.getMode() == AppOpsManager.MODE_FOREGROUND) {
-                                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                                            AppOpsService::notifyOpChanged,
-                                            this, listenerSet.valueAt(cbi), code, uidState.uid,
-                                            uidState.pkgOps.keyAt(pkgi)));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        uidState.state = uidState.pendingState;
-        uidState.capability = uidState.pendingCapability;
-        uidState.appWidgetVisible = uidState.pendingAppWidgetVisible;
-        uidState.pendingStateCommitTime = 0;
-    }
-
     private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
         synchronized (this) {
-            for (int i = uidPackageNames.size() - 1; i >= 0; i--) {
-                final int uid = uidPackageNames.keyAt(i);
-                final UidState uidState = getUidStateLocked(uid, true);
-                if (uidState != null && (uidState.pendingAppWidgetVisible != visible)) {
-                    uidState.pendingAppWidgetVisible = visible;
-                    if (uidState.pendingAppWidgetVisible != uidState.appWidgetVisible) {
-                        commitUidPendingStateLocked(uidState);
-                    }
-                }
-            }
+            getUidStateTracker().updateAppWidgetVisibility(uidPackageNames, visible);
         }
     }
 
@@ -5885,6 +5734,7 @@
         boolean includeDiscreteOps = false;
         int nDiscreteOps = 10;
         @HistoricalOpsRequestFilter int dumpFilter = 0;
+        boolean dumpAll = false;
 
         if (args != null) {
             for (int i = 0; i < args.length; i++) {
@@ -5894,6 +5744,7 @@
                     return;
                 } else if ("-a".equals(arg)) {
                     // dump all data
+                    dumpAll = true;
                 } else if ("--op".equals(arg)) {
                     i++;
                     if (i >= args.length) {
@@ -6207,31 +6058,7 @@
                 }
 
                 pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
-                pw.print("    state=");
-                pw.println(AppOpsManager.getUidStateName(uidState.state));
-                if (uidState.state != uidState.pendingState) {
-                    pw.print("    pendingState=");
-                    pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
-                }
-                pw.print("    capability=");
-                ActivityManager.printCapabilitiesFull(pw, uidState.capability);
-                pw.println();
-                if (uidState.capability != uidState.pendingCapability) {
-                    pw.print("    pendingCapability=");
-                    ActivityManager.printCapabilitiesFull(pw, uidState.pendingCapability);
-                    pw.println();
-                }
-                pw.print("    appWidgetVisible=");
-                pw.println(uidState.appWidgetVisible);
-                if (uidState.appWidgetVisible != uidState.pendingAppWidgetVisible) {
-                    pw.print("    pendingAppWidgetVisible=");
-                    pw.println(uidState.pendingAppWidgetVisible);
-                }
-                if (uidState.pendingStateCommitTime != 0) {
-                    pw.print("    pendingStateCommitTime=");
-                    TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
-                    pw.println();
-                }
+                uidState.dump(pw, nowElapsed);
                 if (uidState.foregroundOps != null && (dumpMode < 0
                         || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
                     pw.println("    foregroundOps:");
@@ -6450,6 +6277,14 @@
             mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
                     dumpFilter, dumpOp, sdf, date, "  ", nDiscreteOps);
         }
+
+        if (dumpAll) {
+            pw.println();
+            pw.println("Uid State Changes Event Log:");
+            if (mUidStateTracker != null) {
+                mUidStateTracker.dumpEvents(pw);
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
new file mode 100644
index 0000000..3da121b
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
+import static android.app.AppOpsManager.UID_STATE_TOP;
+
+import android.os.Handler;
+import android.util.SparseArray;
+
+import java.io.PrintWriter;
+
+interface AppOpsUidStateTracker {
+
+    // Map from process states to the uid states we track.
+    static int processStateToUidState(int procState) {
+        if (procState == PROCESS_STATE_UNKNOWN) {
+            return UID_STATE_CACHED;
+        }
+
+        if (procState <= PROCESS_STATE_PERSISTENT_UI) {
+            return UID_STATE_PERSISTENT;
+        }
+
+        if (procState <= PROCESS_STATE_TOP) {
+            return UID_STATE_TOP;
+        }
+
+        if (procState <= PROCESS_STATE_BOUND_TOP) {
+            return UID_STATE_FOREGROUND;
+        }
+
+        if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) {
+            return UID_STATE_FOREGROUND_SERVICE;
+        }
+
+        if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+            return UID_STATE_FOREGROUND;
+        }
+
+        if (procState <= PROCESS_STATE_RECEIVER) {
+            return UID_STATE_BACKGROUND;
+        }
+
+        return UID_STATE_CACHED;
+    }
+
+    /*
+     * begin data pushed from appopsservice
+     */
+
+    void updateUidProcState(int uid, int procState, int capability);
+
+    void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible);
+
+    /*
+     * end data pushed from appopsservice
+     */
+
+    /**
+     * Gets the {@link android.app.AppOpsManager.UidState} that the uid current is in.
+     */
+    int getUidState(int uid);
+
+    /**
+     * Given a uid, code, and mode, resolve any foregroundness to MODE_IGNORED or MODE_ALLOWED
+     */
+    int evalMode(int uid, int code, int mode);
+
+    /**
+     * Listen to changes in {@link android.app.AppOpsManager.UidState}
+     */
+    void addUidStateChangedCallback(Handler handler,
+            UidStateChangedCallback callback);
+
+    /**
+     * Remove a {@link UidStateChangedCallback}
+     */
+    void removeUidStateChangedCallback(UidStateChangedCallback callback);
+
+    interface UidStateChangedCallback {
+        /**
+         * Invoked when a UID's {@link android.app.AppOpsManager.UidState} changes.
+         * @param uid The uid that changed.
+         * @param uidState The state that was changed to.
+         * @param foregroundModeMayChange True if there may be a op in MODE_FOREGROUND whose
+         *                               evaluated result may have changed.
+         */
+        void onUidStateChanged(int uid, int uidState, boolean foregroundModeMayChange);
+    }
+
+    void dumpUidState(PrintWriter pw, int uid, long nowElapsed);
+
+    void dumpEvents(PrintWriter pw);
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
new file mode 100644
index 0000000..ca5bfb3
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.ProcessCapability;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_TOP;
+
+import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+import android.util.SparseLongArray;
+import android.util.TimeUtils;
+
+import com.android.internal.os.Clock;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+
+class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
+
+    private static final String LOG_TAG = AppOpsUidStateTrackerImpl.class.getSimpleName();
+
+    private final Handler mHandler;
+    private final Clock mClock;
+    private ActivityManagerInternal mActivityManagerInternal;
+    private AppOpsService.Constants mConstants;
+
+    private SparseIntArray mUidStates = new SparseIntArray();
+    private SparseIntArray mPendingUidStates = new SparseIntArray();
+    private SparseIntArray mCapability = new SparseIntArray();
+    private SparseIntArray mPendingCapability = new SparseIntArray();
+    private SparseBooleanArray mVisibleAppWidget = new SparseBooleanArray();
+    private SparseBooleanArray mPendingVisibleAppWidget = new SparseBooleanArray();
+    private SparseLongArray mPendingCommitTime = new SparseLongArray();
+    private SparseBooleanArray mPendingGone = new SparseBooleanArray();
+
+    private ArrayMap<UidStateChangedCallback, Handler> mUidStateChangedCallbacks = new ArrayMap<>();
+
+    private final EventLog mEventLog;
+
+    AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
+            Handler handler, Clock clock, AppOpsService.Constants constants) {
+        mActivityManagerInternal = activityManagerInternal;
+        mHandler = handler;
+        mClock = clock;
+        mConstants = constants;
+
+        mEventLog = new EventLog(handler);
+    }
+
+    @Override
+    public int getUidState(int uid) {
+        return getUidStateLocked(uid);
+    }
+
+    private int getUidStateLocked(int uid) {
+        updateUidPendingStateIfNeeded(uid);
+        return mUidStates.get(uid, UID_STATE_CACHED);
+    }
+
+    @Override
+    public int evalMode(int uid, int code, int mode) {
+        if (mode != AppOpsManager.MODE_FOREGROUND) {
+            return mode;
+        }
+
+        int uidStateValue;
+        int capability;
+        boolean visibleAppWidget;
+        boolean pendingTop;
+        boolean tempAllowlist;
+        uidStateValue = getUidState(uid);
+        capability = getUidCapability(uid);
+        visibleAppWidget = getUidVisibleAppWidget(uid);
+        pendingTop = mActivityManagerInternal.isPendingTopUid(uid);
+        tempAllowlist = mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid);
+
+        int result = evalMode(uidStateValue, code, mode, capability, visibleAppWidget, pendingTop,
+                tempAllowlist);
+        mEventLog.logEvalForegroundMode(uid, uidStateValue, capability, code, result);
+        return result;
+    }
+
+    private static int evalMode(int uidState, int code, int mode, int capability,
+            boolean appWidgetVisible, boolean pendingTop, boolean tempAllowlist) {
+        if (mode != AppOpsManager.MODE_FOREGROUND) {
+            return mode;
+        }
+
+        if (appWidgetVisible || pendingTop || tempAllowlist) {
+            return MODE_ALLOWED;
+        }
+
+        switch (code) {
+            case AppOpsManager.OP_FINE_LOCATION:
+            case AppOpsManager.OP_COARSE_LOCATION:
+            case AppOpsManager.OP_MONITOR_LOCATION:
+            case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
+                if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) == 0) {
+                    return MODE_IGNORED;
+                } else {
+                    return MODE_ALLOWED;
+                }
+            case OP_CAMERA:
+                if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) == 0) {
+                    return MODE_IGNORED;
+                } else {
+                    return MODE_ALLOWED;
+                }
+            case OP_RECORD_AUDIO:
+                if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) == 0) {
+                    return MODE_IGNORED;
+                } else {
+                    return MODE_ALLOWED;
+                }
+        }
+
+        if (uidState > AppOpsManager.resolveFirstUnrestrictedUidState(code)) {
+            return MODE_IGNORED;
+        }
+
+        return MODE_ALLOWED;
+    }
+
+    @Override
+    public void addUidStateChangedCallback(Handler handler, UidStateChangedCallback callback) {
+        if (mUidStateChangedCallbacks.containsKey(callback)) {
+            throw new IllegalStateException("Callback is already registered.");
+        }
+        mUidStateChangedCallbacks.put(callback, handler);
+    }
+
+    @Override
+    public void removeUidStateChangedCallback(UidStateChangedCallback callback) {
+        if (!mUidStateChangedCallbacks.containsKey(callback)) {
+            throw new IllegalStateException("Callback is not registered.");
+        }
+        mUidStateChangedCallbacks.remove(callback);
+    }
+
+    @Override
+    public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
+        int numUids = uidPackageNames.size();
+        for (int i = 0; i < numUids; i++) {
+            int uid = uidPackageNames.keyAt(i);
+            mPendingVisibleAppWidget.put(uid, visible);
+
+            commitUidPendingState(uid);
+        }
+    }
+
+    @Override
+    public void updateUidProcState(int uid, int procState, int capability) {
+        mEventLog.logUpdateUidProcState(uid, procState, capability);
+
+        int uidState = processStateToUidState(procState);
+
+        int prevUidState = mUidStates.get(uid, AppOpsManager.MIN_PRIORITY_UID_STATE);
+        int prevCapability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
+        long pendingStateCommitTime = mPendingCommitTime.get(uid, 0);
+        if (uidState != prevUidState || capability != prevCapability) {
+            mPendingUidStates.put(uid, uidState);
+            mPendingCapability.put(uid, capability);
+
+            if (procState == PROCESS_STATE_NONEXISTENT) {
+                mPendingGone.put(uid, true);
+                commitUidPendingState(uid);
+            } else if (uidState < prevUidState
+                    || (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+                    && prevUidState > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
+                // We are moving to a more important state, or the new state may be in the
+                // foreground and the old state is in the background, then always do it
+                // immediately.
+                commitUidPendingState(uid);
+            } else if (uidState == prevUidState && capability != prevCapability) {
+                // No change on process state, but process capability has changed.
+                commitUidPendingState(uid);
+            } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED) {
+                // We are moving to a less important state, but it doesn't cross the restriction
+                // threshold.
+                commitUidPendingState(uid);
+            } else if (pendingStateCommitTime == 0) {
+                // We are moving to a less important state for the first time,
+                // delay the application for a bit.
+                final long settleTime;
+                if (prevUidState <= UID_STATE_TOP) {
+                    settleTime = mConstants.TOP_STATE_SETTLE_TIME;
+                } else if (prevUidState <= UID_STATE_FOREGROUND_SERVICE) {
+                    settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
+                } else {
+                    settleTime = mConstants.BG_STATE_SETTLE_TIME;
+                }
+                final long commitTime = mClock.elapsedRealtime() + settleTime;
+                mPendingCommitTime.put(uid, commitTime);
+
+                mHandler.sendMessageDelayed(PooledLambda.obtainMessage(
+                                AppOpsUidStateTrackerImpl::updateUidPendingStateIfNeeded, this,
+                                uid), settleTime + 1);
+            }
+        }
+    }
+
+    @Override
+    public void dumpUidState(PrintWriter pw, int uid, long nowElapsed) {
+        int state = mUidStates.get(uid, UID_STATE_CACHED);
+        // if no pendingState set to state to suppress output
+        int pendingState = mPendingUidStates.get(uid, state);
+        pw.print("    state=");
+        pw.println(AppOpsManager.getUidStateName(state));
+        if (state != pendingState) {
+            pw.print("    pendingState=");
+            pw.println(AppOpsManager.getUidStateName(pendingState));
+        }
+        int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
+        // if no pendingCapability set to capability to suppress output
+        int pendingCapability = mPendingCapability.get(uid, capability);
+        pw.print("    capability=");
+        ActivityManager.printCapabilitiesFull(pw, capability);
+        pw.println();
+        if (capability != pendingCapability) {
+            pw.print("    pendingCapability=");
+            ActivityManager.printCapabilitiesFull(pw, pendingCapability);
+            pw.println();
+        }
+        boolean appWidgetVisible = mVisibleAppWidget.get(uid, false);
+        // if no pendingAppWidgetVisible set to appWidgetVisible to suppress output
+        boolean pendingAppWidgetVisible = mPendingVisibleAppWidget.get(uid, appWidgetVisible);
+        pw.print("    appWidgetVisible=");
+        pw.println(appWidgetVisible);
+        if (appWidgetVisible != pendingAppWidgetVisible) {
+            pw.print("    pendingAppWidgetVisible=");
+            pw.println(pendingAppWidgetVisible);
+        }
+        long pendingStateCommitTime = mPendingCommitTime.get(uid, 0);
+        if (pendingStateCommitTime != 0) {
+            pw.print("    pendingStateCommitTime=");
+            TimeUtils.formatDuration(pendingStateCommitTime, nowElapsed, pw);
+            pw.println();
+        }
+    }
+
+    @Override
+    public void dumpEvents(PrintWriter pw) {
+        mEventLog.dumpEvents(pw);
+    }
+
+    private void updateUidPendingStateIfNeeded(int uid) {
+        updateUidPendingStateIfNeededLocked(uid);
+    }
+
+    private void updateUidPendingStateIfNeededLocked(int uid) {
+        long pendingCommitTime = mPendingCommitTime.get(uid, 0);
+        if (pendingCommitTime != 0) {
+            long currentTime = mClock.elapsedRealtime();
+            if (currentTime < mPendingCommitTime.get(uid)) {
+                return;
+            }
+            commitUidPendingState(uid);
+        }
+    }
+
+    private void commitUidPendingState(int uid) {
+        int pendingUidState = mPendingUidStates.get(uid, UID_STATE_CACHED);
+        int pendingCapability = mPendingCapability.get(uid, PROCESS_CAPABILITY_NONE);
+        boolean pendingVisibleAppWidget = mPendingVisibleAppWidget.get(uid, false);
+
+        int uidState = mUidStates.get(uid, UID_STATE_CACHED);
+        int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
+        boolean visibleAppWidget = mVisibleAppWidget.get(uid, false);
+
+        if (uidState != pendingUidState
+                || capability != pendingCapability
+                || visibleAppWidget != pendingVisibleAppWidget) {
+            boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+                    != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+                    || capability != pendingCapability
+                    || visibleAppWidget != pendingVisibleAppWidget;
+
+            if (foregroundChange) {
+                // To save on memory usage, log only interesting changes.
+                mEventLog.logCommitUidState(uid, pendingUidState, pendingCapability,
+                        pendingVisibleAppWidget);
+            }
+
+            for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) {
+                UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i);
+                Handler h = mUidStateChangedCallbacks.valueAt(i);
+
+                h.sendMessage(PooledLambda.obtainMessage(UidStateChangedCallback::onUidStateChanged,
+                        cb, uid, pendingUidState, foregroundChange));
+            }
+        }
+
+        if (mPendingGone.get(uid, false)) {
+            mUidStates.delete(uid);
+            mCapability.delete(uid);
+            mVisibleAppWidget.delete(uid);
+            mPendingGone.delete(uid);
+        } else {
+            mUidStates.put(uid, pendingUidState);
+            mCapability.put(uid, pendingCapability);
+            mVisibleAppWidget.put(uid, pendingVisibleAppWidget);
+        }
+
+        mPendingUidStates.delete(uid);
+        mPendingCapability.delete(uid);
+        mPendingVisibleAppWidget.delete(uid);
+        mPendingCommitTime.delete(uid);
+    }
+
+    private @ProcessCapability int getUidCapability(int uid) {
+        return mCapability.get(uid, ActivityManager.PROCESS_CAPABILITY_NONE);
+    }
+
+    private boolean getUidVisibleAppWidget(int uid) {
+        return mVisibleAppWidget.get(uid, false);
+    }
+
+    private static class EventLog {
+
+        // These seems a bit too verbose and not as useful, turning off for now.
+        // DCE should be able to remove most associated code.
+        // Memory usage: 16 * size bytes
+        private static final int UPDATE_UID_PROC_STATE_LOG_MAX_SIZE = 0;
+        // Memory usage: 20 * size bytes
+        private static final int COMMIT_UID_STATE_LOG_MAX_SIZE = 200;
+        // Memory usage: 24 * size bytes
+        private static final int EVAL_FOREGROUND_MODE_MAX_SIZE = 200;
+
+        private final Handler mHandler;
+
+        private int[][] mUpdateUidProcStateLog = new int[UPDATE_UID_PROC_STATE_LOG_MAX_SIZE][3];
+        private long[] mUpdateUidProcStateLogTimestamps =
+                new long[UPDATE_UID_PROC_STATE_LOG_MAX_SIZE];
+        private int mUpdateUidProcStateLogSize = 0;
+        private int mUpdateUidProcStateLogHead = 0;
+
+        private int[][] mCommitUidStateLog = new int[COMMIT_UID_STATE_LOG_MAX_SIZE][4];
+        private long[] mCommitUidStateLogTimestamps = new long[COMMIT_UID_STATE_LOG_MAX_SIZE];
+        private int mCommitUidStateLogSize = 0;
+        private int mCommitUidStateLogHead = 0;
+
+        private int[][] mEvalForegroundModeLog = new int[EVAL_FOREGROUND_MODE_MAX_SIZE][5];
+        private long[] mEvalForegroundModeLogTimestamps = new long[EVAL_FOREGROUND_MODE_MAX_SIZE];
+        private int mEvalForegroundModeLogSize = 0;
+        private int mEvalForegroundModeLogHead = 0;
+
+        EventLog(Handler handler) {
+            mHandler = handler;
+        }
+
+        void logUpdateUidProcState(int uid, int procState, int capability) {
+            if (UPDATE_UID_PROC_STATE_LOG_MAX_SIZE == 0) {
+                return;
+            }
+            mHandler.sendMessage(PooledLambda.obtainMessage(EventLog::logUpdateUidProcStateAsync,
+                    this, System.currentTimeMillis(), uid, procState, capability));
+        }
+
+        void logUpdateUidProcStateAsync(long timestamp, int uid, int procState, int capability) {
+            int idx = (mUpdateUidProcStateLogHead + mUpdateUidProcStateLogSize)
+                    % UPDATE_UID_PROC_STATE_LOG_MAX_SIZE;
+            if (mUpdateUidProcStateLogSize == UPDATE_UID_PROC_STATE_LOG_MAX_SIZE) {
+                mUpdateUidProcStateLogHead =
+                        (mUpdateUidProcStateLogHead + 1) % UPDATE_UID_PROC_STATE_LOG_MAX_SIZE;
+            } else {
+                mUpdateUidProcStateLogSize++;
+            }
+
+            mUpdateUidProcStateLog[idx][0] = uid;
+            mUpdateUidProcStateLog[idx][1] = procState;
+            mUpdateUidProcStateLog[idx][2] = capability;
+            mUpdateUidProcStateLogTimestamps[idx] = timestamp;
+        }
+
+        void logCommitUidState(int uid, int uidState, int capability, boolean visible) {
+            if (COMMIT_UID_STATE_LOG_MAX_SIZE == 0) {
+                return;
+            }
+            mHandler.sendMessage(PooledLambda.obtainMessage(EventLog::logCommitUidStateAsync,
+                    this, System.currentTimeMillis(), uid, uidState, capability, visible));
+        }
+
+        void logCommitUidStateAsync(long timestamp, int uid, int uidState, int capability,
+                boolean visible) {
+            int idx = (mCommitUidStateLogHead + mCommitUidStateLogSize)
+                    % COMMIT_UID_STATE_LOG_MAX_SIZE;
+            if (mCommitUidStateLogSize == COMMIT_UID_STATE_LOG_MAX_SIZE) {
+                mCommitUidStateLogHead =
+                        (mCommitUidStateLogHead + 1) % COMMIT_UID_STATE_LOG_MAX_SIZE;
+            } else {
+                mCommitUidStateLogSize++;
+            }
+
+            mCommitUidStateLog[idx][0] = uid;
+            mCommitUidStateLog[idx][1] = uidState;
+            mCommitUidStateLog[idx][2] = capability;
+            mCommitUidStateLog[idx][3] = visible ? 1 : 0;
+            mCommitUidStateLogTimestamps[idx] = timestamp;
+        }
+
+        void logEvalForegroundMode(int uid, int uidState, int capability, int code, int result) {
+            if (EVAL_FOREGROUND_MODE_MAX_SIZE == 0) {
+                return;
+            }
+            mHandler.sendMessage(PooledLambda.obtainMessage(EventLog::logEvalForegroundModeAsync,
+                    this, System.currentTimeMillis(), uid, uidState, capability, code, result));
+        }
+
+        void logEvalForegroundModeAsync(long timestamp, int uid, int uidState, int capability,
+                int code, int result) {
+            int idx = (mEvalForegroundModeLogHead + mEvalForegroundModeLogSize)
+                    % EVAL_FOREGROUND_MODE_MAX_SIZE;
+            if (mEvalForegroundModeLogSize == EVAL_FOREGROUND_MODE_MAX_SIZE) {
+                mEvalForegroundModeLogHead =
+                        (mEvalForegroundModeLogHead + 1) % EVAL_FOREGROUND_MODE_MAX_SIZE;
+            } else {
+                mEvalForegroundModeLogSize++;
+            }
+
+            mEvalForegroundModeLog[idx][0] = uid;
+            mEvalForegroundModeLog[idx][1] = uidState;
+            mEvalForegroundModeLog[idx][2] = capability;
+            mEvalForegroundModeLog[idx][3] = code;
+            mEvalForegroundModeLog[idx][4] = result;
+            mEvalForegroundModeLogTimestamps[idx] = timestamp;
+        }
+
+        void dumpEvents(PrintWriter pw) {
+            if (Thread.currentThread() != mHandler.getLooper().getThread()) {
+                // All operations are done on the handler's thread
+                CountDownLatch latch = new CountDownLatch(1);
+                mHandler.post(() -> {
+                    dumpEvents(pw);
+                    latch.countDown();
+                });
+
+                try {
+                    latch.await();
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+                return;
+            }
+
+            int updateIdx = 0;
+            int commitIdx = 0;
+            int evalIdx = 0;
+
+            while (updateIdx < mUpdateUidProcStateLogSize
+                    || commitIdx < mCommitUidStateLogSize
+                    || evalIdx < mEvalForegroundModeLogSize) {
+                int updatePtr = 0;
+                int commitPtr = 0;
+                int evalPtr = 0;
+                if (UPDATE_UID_PROC_STATE_LOG_MAX_SIZE != 0) {
+                    updatePtr = (mUpdateUidProcStateLogHead + updateIdx)
+                            % UPDATE_UID_PROC_STATE_LOG_MAX_SIZE;
+                }
+                if (COMMIT_UID_STATE_LOG_MAX_SIZE != 0) {
+                    commitPtr = (mCommitUidStateLogHead + commitIdx)
+                            % COMMIT_UID_STATE_LOG_MAX_SIZE;
+                }
+                if (EVAL_FOREGROUND_MODE_MAX_SIZE != 0) {
+                    evalPtr = (mEvalForegroundModeLogHead + evalIdx)
+                            % EVAL_FOREGROUND_MODE_MAX_SIZE;
+                }
+
+                long aTimestamp = updateIdx < mUpdateUidProcStateLogSize
+                        ? mUpdateUidProcStateLogTimestamps[updatePtr] : Long.MAX_VALUE;
+                long bTimestamp = commitIdx < mCommitUidStateLogSize
+                        ? mCommitUidStateLogTimestamps[commitPtr] : Long.MAX_VALUE;
+                long cTimestamp = evalIdx < mEvalForegroundModeLogSize
+                        ? mEvalForegroundModeLogTimestamps[evalPtr] : Long.MAX_VALUE;
+
+                if (aTimestamp <= bTimestamp && aTimestamp <= cTimestamp) {
+                    dumpUpdateUidProcState(pw, updatePtr);
+                    updateIdx++;
+                } else if (bTimestamp <= cTimestamp) {
+                    dumpCommitUidState(pw, commitPtr);
+                    commitIdx++;
+                } else {
+                    dumpEvalForegroundMode(pw, evalPtr);
+                    evalIdx++;
+                }
+            }
+        }
+
+        void dumpUpdateUidProcState(PrintWriter pw, int idx) {
+            long timestamp = mUpdateUidProcStateLogTimestamps[idx];
+            int uid = mUpdateUidProcStateLog[idx][0];
+            int procState = mUpdateUidProcStateLog[idx][1];
+            int capability = mUpdateUidProcStateLog[idx][2];
+
+            TimeUtils.dumpTime(pw, timestamp);
+
+            pw.print(" UPDATE_UID_PROC_STATE");
+
+            pw.print(" uid=");
+            pw.print(uid);
+
+            pw.print(" procState=");
+            pw.print(String.format("%-30s", ActivityManager.procStateToString(procState)));
+
+            pw.print(" capability=");
+            pw.print(ActivityManager.getCapabilitiesSummary(capability));
+
+            pw.println();
+        }
+
+        void dumpCommitUidState(PrintWriter pw, int idx) {
+            long timestamp = mCommitUidStateLogTimestamps[idx];
+            int uid = mCommitUidStateLog[idx][0];
+            int uidState = mCommitUidStateLog[idx][1];
+            int capability = mCommitUidStateLog[idx][2];
+            boolean visibleAppWidget = mCommitUidStateLog[idx][3] != 0;
+
+            TimeUtils.dumpTime(pw, timestamp);
+
+            pw.print(" COMMIT_UID_STATE     ");
+
+            pw.print(" uid=");
+            pw.print(uid);
+
+            pw.print(" uidState=");
+            pw.print(String.format("%-30s", AppOpsManager.uidStateToString(uidState)));
+
+            pw.print(" capability=");
+            pw.print(ActivityManager.getCapabilitiesSummary(capability));
+
+            pw.print(" visibleAppWidget=");
+            pw.print(visibleAppWidget);
+
+            pw.println();
+        }
+
+        void dumpEvalForegroundMode(PrintWriter pw, int idx) {
+            long timestamp = mEvalForegroundModeLogTimestamps[idx];
+            int uid = mEvalForegroundModeLog[idx][0];
+            int uidState = mEvalForegroundModeLog[idx][1];
+            int capability = mEvalForegroundModeLog[idx][2];
+            int code = mEvalForegroundModeLog[idx][3];
+            int result = mEvalForegroundModeLog[idx][4];
+
+            TimeUtils.dumpTime(pw, timestamp);
+
+            pw.print(" EVAL_FOREGROUND_MODE ");
+
+            pw.print(" uid=");
+            pw.print(uid);
+
+            pw.print(" uidState=");
+            pw.print(String.format("%-30s", AppOpsManager.uidStateToString(uidState)));
+
+            pw.print(" capability=");
+            pw.print(ActivityManager.getCapabilitiesSummary(capability));
+
+            pw.print(" code=");
+            pw.print(String.format("%-20s", AppOpsManager.opToName(code)));
+
+            pw.print(" result=");
+            pw.print(AppOpsManager.modeToName(result));
+
+            pw.println();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index e97d9c2..736914a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -17,9 +17,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.compat.CompatChanges;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothProfile;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -118,8 +121,39 @@
     // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
     /*package*/ final Object mSetModeLock = new Object();
 
-    /** PID of current audio mode owner communicated by AudioService */
-    private int mModeOwnerPid = 0;
+    /** AudioModeInfo contains information on current audio mode owner
+     * communicated by AudioService */
+    /* package */ static final class AudioModeInfo {
+        /** Current audio mode */
+        final int mMode;
+        /** PID of current audio mode owner */
+        final int mPid;
+        /** UID of current audio mode owner */
+        final int mUid;
+
+        AudioModeInfo(int mode, int pid, int uid) {
+            mMode = mode;
+            mPid = pid;
+            mUid = uid;
+        }
+
+        @Override
+        public String toString() {
+            return "AudioModeInfo: mMode=" + AudioSystem.modeToString(mMode)
+                    + ", mPid=" + mPid
+                    + ", mUid=" + mUid;
+        }
+    };
+
+    private AudioModeInfo mAudioModeOwner = new AudioModeInfo(AudioSystem.MODE_NORMAL, 0, 0);
+
+    /**
+     * Indicates that default communication device is chosen by routing rules in audio policy
+     * manager and not forced by AudioDeviceBroker.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+    public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L;
 
     //-------------------------------------------------------------------
     /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
@@ -187,7 +221,7 @@
     /*package*/ void onSystemReady() {
         synchronized (mSetModeLock) {
             synchronized (mDeviceStateLock) {
-                mModeOwnerPid = mAudioService.getModeOwnerPid();
+                mAudioModeOwner = mAudioService.getAudioModeOwner();
                 mBtHelper.onSystemReady();
             }
         }
@@ -368,11 +402,11 @@
     @GuardedBy("mDeviceStateLock")
     private CommunicationRouteClient topCommunicationRouteClient() {
         for (CommunicationRouteClient crc : mCommunicationRouteClients) {
-            if (crc.getPid() == mModeOwnerPid) {
+            if (crc.getPid() == mAudioModeOwner.mPid) {
                 return crc;
             }
         }
-        if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
+        if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) {
             return mCommunicationRouteClients.get(0);
         }
         return null;
@@ -390,7 +424,7 @@
         AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "requestedCommunicationDevice, device: "
-                    + device + " mode owner pid: " + mModeOwnerPid);
+                    + device + "mAudioModeOwner: " + mAudioModeOwner.toString());
         }
         return device;
     }
@@ -774,8 +808,9 @@
         sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
     }
 
-    /*package*/ void postSetModeOwnerPid(int pid, int mode) {
-        sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
+    /*package*/ void postSetModeOwner(int mode, int pid, int uid) {
+        sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE,
+                new AudioModeInfo(mode, pid, uid));
     }
 
     /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -1162,7 +1197,7 @@
         pw.println(prefix + "mAccessibilityStrategyId: "
                 +  mAccessibilityStrategyId);
 
-        pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);
+        pw.println("\n" + prefix + "mAudioModeOwner: " + mAudioModeOwner);
 
         mBtHelper.dump(pw, prefix);
     }
@@ -1288,12 +1323,19 @@
                     }
                     break;
                 case MSG_L_SET_BT_ACTIVE_DEVICE:
-                    synchronized (mDeviceStateLock) {
-                        BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
-                        mDeviceInventory.onSetBtActiveDevice(btInfo,
-                                (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
-                                        ? mAudioService.getBluetoothContextualVolumeStream()
-                                        : AudioSystem.STREAM_DEFAULT);
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
+                            mDeviceInventory.onSetBtActiveDevice(btInfo,
+                                    (btInfo.mProfile
+                                            != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
+                                            ? mAudioService.getBluetoothContextualVolumeStream()
+                                            : AudioSystem.STREAM_DEFAULT);
+                            if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
+                                    || btInfo.mProfile == BluetoothProfile.HEARING_AID) {
+                                onUpdateCommunicationRouteClient("setBluetoothActiveDevice");
+                            }
+                        }
                     }
                     break;
                 case MSG_BT_HEADSET_CNCT_FAILED:
@@ -1338,11 +1380,11 @@
                         mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
                     }
                     break;
-                case MSG_I_SET_MODE_OWNER_PID:
+                case MSG_I_SET_MODE_OWNER:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            mModeOwnerPid = msg.arg1;
-                            if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
+                            mAudioModeOwner = (AudioModeInfo) msg.obj;
+                            if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
                                 onUpdateCommunicationRouteClient("setNewModeOwner");
                             }
                         }
@@ -1504,7 +1546,7 @@
     private static final int MSG_REPORT_NEW_ROUTES = 13;
     private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
     private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
-    private static final int MSG_I_SET_MODE_OWNER_PID = 16;
+    private static final int MSG_I_SET_MODE_OWNER = 16;
 
     private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
     private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
@@ -1826,8 +1868,16 @@
             AudioSystem.setParameters("BT_SCO=on");
         }
         if (preferredCommunicationDevice == null) {
-            removePreferredDevicesForStrategySync(mCommunicationStrategyId);
-            removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
+            AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
+            if (defaultDevice != null) {
+                setPreferredDevicesForStrategySync(
+                        mCommunicationStrategyId, Arrays.asList(defaultDevice));
+                setPreferredDevicesForStrategySync(
+                        mAccessibilityStrategyId, Arrays.asList(defaultDevice));
+            } else {
+                removePreferredDevicesForStrategySync(mCommunicationStrategyId);
+                removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
+            }
         } else {
             setPreferredDevicesForStrategySync(
                     mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
@@ -1856,26 +1906,24 @@
         }
     }
 
+    // @GuardedBy("mSetModeLock")
+    @GuardedBy("mDeviceStateLock")
     private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
-        synchronized (mSetModeLock) {
-            synchronized (mDeviceStateLock) {
-                boolean wasSpeakerphoneActive = isSpeakerphoneActive();
-                mPreferredCommunicationDevice = device;
-                updateActiveCommunicationDevice();
-                if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
-                    try {
-                        mContext.sendBroadcastAsUser(
-                                new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
-                                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
-                                                  UserHandle.ALL);
-                    } catch (Exception e) {
-                        Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
-                    }
-                }
-                mAudioService.postUpdateRingerModeServiceInt();
-                dispatchCommunicationDevice();
+        boolean wasSpeakerphoneActive = isSpeakerphoneActive();
+        mPreferredCommunicationDevice = device;
+        updateActiveCommunicationDevice();
+        if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
+            try {
+                mContext.sendBroadcastAsUser(
+                        new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+                                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+                                          UserHandle.ALL);
+            } catch (Exception e) {
+                Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
             }
         }
+        mAudioService.postUpdateRingerModeServiceInt();
+        dispatchCommunicationDevice();
     }
 
     private CommunicationRouteClient removeCommunicationRouteClient(
@@ -1915,6 +1963,32 @@
         return null;
     }
 
+    @GuardedBy("mDeviceStateLock")
+    private boolean communnicationDeviceCompatOn() {
+        return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
+                && !(CompatChanges.isChangeEnabled(
+                        USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
+                     || mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
+    }
+
+    @GuardedBy("mDeviceStateLock")
+    AudioDeviceAttributes getDefaultCommunicationDevice() {
+        // For system server (Telecom) and APKs targeting S and above, we let the audio
+        // policy routing rules select the default communication device.
+        // For older APKs, we force Hearing Aid or LE Audio headset when connected as
+        // those APKs cannot select a LE Audio or Hearing Aid device explicitly.
+        AudioDeviceAttributes device = null;
+        if (communnicationDeviceCompatOn()) {
+            // If both LE and Hearing Aid are active (thie should not happen),
+            // priority to Hearing Aid.
+            device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
+            if (device == null) {
+                device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
+            }
+        }
+        return device;
+    }
+
     @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
         synchronized (mDeviceStateLock) {
             return mDeviceInventory.getDeviceSensorUuid(device);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index c1f4969..e90bfe8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -294,6 +294,7 @@
         }
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
     @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) {
         if (AudioService.DEBUG_DEVICES) {
@@ -1526,6 +1527,19 @@
             return di.mSensorUuid;
         }
     }
+
+    /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
+        synchronized (mDevicesLock) {
+            for (DeviceInfo di : mConnectedDevices.values()) {
+                if (di.mDeviceType == type) {
+                    return new AudioDeviceAttributes(
+                            di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
+                }
+            }
+        }
+        return null;
+    }
+
     //----------------------------------------------------------
     // For tests only
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ec8bf55..c8aecaf 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3360,8 +3360,7 @@
                 dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
             }
 
-            if ((device == AudioSystem.DEVICE_OUT_BLE_HEADSET
-                    || device == AudioSystem.DEVICE_OUT_BLE_BROADCAST)
+            if (AudioSystem.isLeAudioDeviceType(device)
                     && streamType == getBluetoothContextualVolumeStream()
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
@@ -4117,8 +4116,7 @@
                 dispatchAbsoluteVolumeChanged(streamType, info, index);
             }
 
-            if ((device == AudioSystem.DEVICE_OUT_BLE_HEADSET
-                    || device == AudioSystem.DEVICE_OUT_BLE_BROADCAST)
+            if (AudioSystem.isLeAudioDeviceType(device)
                     && streamType == getBluetoothContextualVolumeStream()
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
@@ -5232,16 +5230,17 @@
     }
 
     /**
-     * Return the pid of the current audio mode owner
+     * Return information on the current audio mode owner
      * @return 0 if nobody owns the mode
      */
     @GuardedBy("mDeviceBroker.mSetModeLock")
-    /*package*/ int getModeOwnerPid() {
+    /*package*/ AudioDeviceBroker.AudioModeInfo getAudioModeOwner() {
         SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
         if (hdlr != null) {
-            return hdlr.getPid();
+            return new AudioDeviceBroker.AudioModeInfo(
+                    hdlr.getMode(), hdlr.getPid(), hdlr.getUid());
         }
-        return 0;
+        return new AudioDeviceBroker.AudioModeInfo(AudioSystem.MODE_NORMAL, 0 , 0);
     }
 
     /**
@@ -5427,7 +5426,7 @@
 
                 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
                 // connections not started by the application changing the mode when pid changes
-                mDeviceBroker.postSetModeOwnerPid(pid, mode);
+                mDeviceBroker.postSetModeOwner(mode, pid, uid);
             } else {
                 Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
             }
@@ -5755,7 +5754,10 @@
         }
         return deviceIds.stream().mapToInt(Integer::intValue).toArray();
     }
-        /** @see AudioManager#setCommunicationDevice(int) */
+        /**
+         * @see AudioManager#setCommunicationDevice(int)
+         * @see AudioManager#clearCommunicationDevice()
+         */
     public boolean setCommunicationDevice(IBinder cb, int portId) {
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
@@ -5770,7 +5772,8 @@
                 throw new IllegalArgumentException("invalid device type " + device.getType());
             }
         }
-        final String eventSource = new StringBuilder("setCommunicationDevice(")
+        final String eventSource = new StringBuilder()
+                .append(device == null ? "clearCommunicationDevice(" : "setCommunicationDevice(")
                 .append(") from u/pid:").append(uid).append("/")
                 .append(pid).toString();
 
@@ -6957,7 +6960,8 @@
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
         }
         if (isAbsoluteVolumeDevice(audioSystemDeviceOut)
-                || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)) {
+                || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)
+                || AudioSystem.isLeAudioDeviceType(audioSystemDeviceOut)) {
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
         }
         return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE;
@@ -7724,7 +7728,9 @@
             int index;
             if (isFullyMuted()) {
                 index = 0;
-            } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)) {
+            } else if (isAbsoluteVolumeDevice(device)
+                    || isA2dpAbsoluteVolumeDevice(device)
+                    || AudioSystem.isLeAudioDeviceType(device)) {
                 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
             } else if (isFullVolumeDevice(device)) {
                 index = (mIndexMax + 5)/10;
@@ -7746,7 +7752,8 @@
                         if (isFullyMuted()) {
                             index = 0;
                         } else if (isAbsoluteVolumeDevice(device)
-                                || isA2dpAbsoluteVolumeDevice(device)) {
+                                || isA2dpAbsoluteVolumeDevice(device)
+                                || AudioSystem.isLeAudioDeviceType(device)) {
                             index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
                         } else if (isFullVolumeDevice(device)) {
                             index = (mIndexMax + 5)/10;
@@ -8167,7 +8174,8 @@
                     int streamDevice = getDeviceForStream(streamType);
                     if ((device != streamDevice)
                             && (isAbsoluteVolumeDevice(device)
-                            || isA2dpAbsoluteVolumeDevice(device))) {
+                                || isA2dpAbsoluteVolumeDevice(device)
+                                || AudioSystem.isLeAudioDeviceType(device))) {
                         mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                     }
                     mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index b5835ce..30a9e0a7 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -433,7 +433,7 @@
                 case VOL_SET_LE_AUDIO_VOL:
                     return new StringBuilder("setLeAudioVolume:")
                             .append(" index:").append(mVal1)
-                            .append(" gain dB:").append(mVal2)
+                            .append(" maxIndex:").append(mVal2)
                             .toString();
                 case VOL_SET_AVRCP_VOL:
                     return new StringBuilder("setAvrcpVolume:")
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 4adbfaa..6e85361 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -410,9 +410,8 @@
             }
             return;
         }
-        /* leaudio expect volume value in range 0 to 255
-         */
-        int volume = (index * (BT_LE_AUDIO_MAX_VOL - BT_LE_AUDIO_MIN_VOL)) / maxIndex ;
+        /* leaudio expect volume value in range 0 to 255 */
+        int volume = (int) Math.round((double) index * BT_LE_AUDIO_MAX_VOL / maxIndex);
 
         if (AudioService.DEBUG_VOL) {
             Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx="
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 4559c56..e5d40d9 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -64,6 +64,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.function.Consumer;
 
 /**
@@ -119,11 +120,7 @@
     private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
             new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
 
-    private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
-    // a public client is one that needs an anonymized version of the playback configurations, we
-    // keep track of whether there is at least one to know when we need to create the list of
-    // playback configurations that do not contain uid/pid/package name information.
-    private boolean mHasPublicClients = false;
+    private final ConcurrentLinkedQueue<PlayMonitorClient> mClients = new ConcurrentLinkedQueue<>();
 
     private final Object mPlayerLock = new Object();
     @GuardedBy("mPlayerLock")
@@ -550,11 +547,9 @@
                 + DateFormat.getTimeInstance().format(new Date()));
         synchronized(mPlayerLock) {
             pw.println("\n  playback listeners:");
-            synchronized(mClients) {
-                for (PlayMonitorClient pmc : mClients) {
-                    pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)")
-                            + pmc.toString());
-                }
+            for (PlayMonitorClient pmc : mClients) {
+                pw.print(" " + (pmc.isPrivileged() ? "(S)" : "(P)")
+                        + pmc.toString());
             }
             pw.println("\n");
             // all players
@@ -635,48 +630,33 @@
      * @param iplayerReleased indicates if the change was due to a player being released
      */
     private void dispatchPlaybackChange(boolean iplayerReleased) {
-        synchronized (mClients) {
-            // typical use case, nobody is listening, don't do any work
-            if (mClients.isEmpty()) {
-                return;
-            }
-        }
         if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
         final List<AudioPlaybackConfiguration> configsSystem;
-        // list of playback configurations for "public consumption". It is only computed if there
+        // list of playback configurations for "public consumption". It is computed lazy if there
         // are non-system playback activity listeners.
-        final List<AudioPlaybackConfiguration> configsPublic;
+        List<AudioPlaybackConfiguration> configsPublic = null;
         synchronized (mPlayerLock) {
             if (mPlayers.isEmpty()) {
                 return;
             }
-            configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
+            configsSystem = new ArrayList<>(mPlayers.values());
         }
-        synchronized (mClients) {
-            // was done at beginning of method, but could have changed
-            if (mClients.isEmpty()) {
-                return;
-            }
-            configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
-            final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
-            while (clientIterator.hasNext()) {
-                final PlayMonitorClient pmc = clientIterator.next();
-                try {
-                    // do not spam the logs if there are problems communicating with this client
-                    if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
-                        if (pmc.mIsPrivileged) {
-                            pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
-                                    iplayerReleased);
-                        } else {
-                            // non-system clients don't have the control interface IPlayer, so
-                            // they don't need to flush commands when a player was released
-                            pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
-                        }
+
+        final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
+        while (clientIterator.hasNext()) {
+            final PlayMonitorClient pmc = clientIterator.next();
+            // do not spam the logs if there are problems communicating with this client
+            if (!pmc.reachedMaxErrorCount()) {
+                if (pmc.isPrivileged()) {
+                    pmc.dispatchPlaybackConfigChange(configsSystem,
+                            iplayerReleased);
+                } else {
+                    if (configsPublic == null) {
+                        configsPublic = anonymizeForPublicConsumption(configsSystem);
                     }
-                } catch (RemoteException e) {
-                    pmc.mErrorCount++;
-                    Log.e(TAG, "Error (" + pmc.mErrorCount +
-                            ") trying to dispatch playback config change to " + pmc, e);
+                    // non-system clients don't have the control interface IPlayer, so
+                    // they don't need to flush commands when a player was released
+                    pmc.dispatchPlaybackConfigChange(configsPublic, false);
                 }
             }
         }
@@ -899,14 +879,9 @@
         if (pcdb == null) {
             return;
         }
-        synchronized(mClients) {
-            final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
-            if (pmc.init()) {
-                if (!isPrivileged) {
-                    mHasPublicClients = true;
-                }
-                mClients.add(pmc);
-            }
+        final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
+        if (pmc.init()) {
+            mClients.add(pmc);
         }
     }
 
@@ -914,23 +889,14 @@
         if (pcdb == null) {
             return;
         }
-        synchronized(mClients) {
-            final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
-            boolean hasPublicClients = false;
-            // iterate over the clients to remove the dispatcher to remove, and reevaluate at
-            // the same time if we still have a public client.
-            while (clientIterator.hasNext()) {
-                PlayMonitorClient pmc = clientIterator.next();
-                if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) {
-                    pmc.release();
-                    clientIterator.remove();
-                } else {
-                    if (!pmc.mIsPrivileged) {
-                        hasPublicClients = true;
-                    }
-                }
+        final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
+        // iterate over the clients to remove the dispatcher
+        while (clientIterator.hasNext()) {
+            PlayMonitorClient pmc = clientIterator.next();
+            if (pmc.equalsDispatcher(pcdb)) {
+                pmc.release();
+                clientIterator.remove();
             }
-            mHasPublicClients = hasPublicClients;
         }
     }
 
@@ -958,24 +924,34 @@
         // can afford to be static because only one PlaybackActivityMonitor ever instantiated
         static PlaybackActivityMonitor sListenerDeathMonitor;
 
-        final IPlaybackConfigDispatcher mDispatcherCb;
-        final boolean mIsPrivileged;
-
-        int mErrorCount = 0;
         // number of errors after which we don't update this client anymore to not spam the logs
-        static final int MAX_ERRORS = 5;
+        private static final int MAX_ERRORS = 5;
+
+        private final IPlaybackConfigDispatcher mDispatcherCb;
+
+        @GuardedBy("this")
+        private final boolean mIsPrivileged;
+        @GuardedBy("this")
+        private boolean mIsReleased = false;
+        @GuardedBy("this")
+        private int mErrorCount = 0;
 
         PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
             mDispatcherCb = pcdb;
             mIsPrivileged = isPrivileged;
         }
 
+        @Override
         public void binderDied() {
             Log.w(TAG, "client died");
             sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb);
         }
 
-        boolean init() {
+        synchronized boolean init() {
+            if (mIsReleased) {
+                // Do not init after release
+                return false;
+            }
             try {
                 mDispatcherCb.asBinder().linkToDeath(this, 0);
                 return true;
@@ -985,8 +961,43 @@
             }
         }
 
-        void release() {
+        synchronized void release() {
             mDispatcherCb.asBinder().unlinkToDeath(this, 0);
+            mIsReleased = true;
+        }
+
+        void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
+                boolean flush) {
+            synchronized (this) {
+                if (mIsReleased) {
+                    // Do not dispatch anything after release
+                    return;
+                }
+            }
+            try {
+                mDispatcherCb.dispatchPlaybackConfigChange(configs, flush);
+            } catch (RemoteException e) {
+                synchronized (this) {
+                    mErrorCount++;
+                    Log.e(TAG, "Error (" + mErrorCount
+                            + ") trying to dispatch playback config change to " + this, e);
+                }
+            }
+        }
+
+        synchronized boolean isPrivileged() {
+            return mIsPrivileged;
+        }
+
+        synchronized boolean reachedMaxErrorCount() {
+            return mErrorCount >= MAX_ERRORS;
+        }
+
+        synchronized boolean equalsDispatcher(IPlaybackConfigDispatcher pcdb) {
+            if (pcdb == null) {
+                return false;
+            }
+            return pcdb.asBinder().equals(mDispatcherCb.asBinder());
         }
     }
 
@@ -1139,18 +1150,29 @@
                     }
                     return builder.toString();
                 case AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED:
-                    builder.append(" muteFromMasterMute:").append(
-                            (mEventValue & PLAYER_MUTE_MASTER) != 0);
-                    builder.append(" muteFromStreamVolume:").append(
-                            (mEventValue & PLAYER_MUTE_STREAM_VOLUME) != 0);
-                    builder.append(" muteFromStreamMute:").append(
-                            (mEventValue & PLAYER_MUTE_STREAM_MUTED) != 0);
-                    builder.append(" muteFromPlaybackRestricted:").append(
-                            (mEventValue & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0);
-                    builder.append(" muteFromClientVolume:").append(
-                            (mEventValue & PLAYER_MUTE_CLIENT_VOLUME) != 0);
-                    builder.append(" muteFromVolumeShaper:").append(
-                            (mEventValue & PLAYER_MUTE_VOLUME_SHAPER) != 0);
+                    builder.append(" source:");
+                    if (mEventValue <= 0) {
+                        builder.append("none ");
+                    } else {
+                        if ((mEventValue & PLAYER_MUTE_MASTER) != 0) {
+                            builder.append("masterMute ");
+                        }
+                        if ((mEventValue & PLAYER_MUTE_STREAM_VOLUME) != 0) {
+                            builder.append("streamVolume ");
+                        }
+                        if ((mEventValue & PLAYER_MUTE_STREAM_MUTED) != 0) {
+                            builder.append("streamMute ");
+                        }
+                        if ((mEventValue & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0) {
+                            builder.append("playbackRestricted ");
+                        }
+                        if ((mEventValue & PLAYER_MUTE_CLIENT_VOLUME) != 0) {
+                            builder.append("clientVolume ");
+                        }
+                        if ((mEventValue & PLAYER_MUTE_VOLUME_SHAPER) != 0) {
+                            builder.append("volumeShaper ");
+                        }
+                    }
                     return builder.toString();
                 default:
                     return builder.toString();
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
index 4779f6f..6a2731d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
@@ -216,19 +216,31 @@
             return null;
         }
 
-        if (mAllProps.size() > 1) {
-            Slog.e(TAG, "getSingleProvider() called but multiple sensors present: "
-                    + mAllProps.size());
-        }
+        // TODO(b/242837110): remove the try-catch once the bug is fixed.
+        try {
+            if (mAllProps.size() > 1) {
+                Slog.e(TAG, "getSingleProvider() called but multiple sensors present: "
+                        + mAllProps.size());
+            }
 
-        final int sensorId = mAllProps.get(0).sensorId;
-        final T provider = getProviderForSensor(sensorId);
-        if (provider != null) {
-            return new Pair<>(sensorId, provider);
-        }
+            final int sensorId = mAllProps.get(0).sensorId;
+            final T provider = getProviderForSensor(sensorId);
+            if (provider != null) {
+                return new Pair<>(sensorId, provider);
+            }
 
-        Slog.e(TAG, "Single sensor: " + sensorId + ", but provider not found");
-        return null;
+            Slog.e(TAG, "Single sensor: " + sensorId + ", but provider not found");
+            return null;
+        } catch (NullPointerException e) {
+            final String extra;
+            if (mAllProps == null) {
+                extra = "mAllProps: null";
+            } else {
+                extra = "mAllProps.size(): " + mAllProps.size();
+            }
+            Slog.e(TAG, "This shouldn't happen. " + extra, e);
+            throw e;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 46d863d..2e1a363 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -59,7 +59,7 @@
 
     // The following apply to all clients
 
-    void onAcquired(int sensorId, int acquiredInfo, int vendorCode) throws RemoteException {
+    public void onAcquired(int sensorId, int acquiredInfo, int vendorCode) throws RemoteException {
         if (mSensorReceiver != null) {
             mSensorReceiver.onAcquired(sensorId, acquiredInfo, vendorCode);
         } else if (mFaceServiceReceiver != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index e0393b5..612d906 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -50,12 +50,14 @@
 import com.android.server.biometrics.sensors.EnrollClient;
 import com.android.server.biometrics.sensors.SensorOverlays;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
+import com.android.server.biometrics.sensors.fingerprint.PowerPressHandler;
 import com.android.server.biometrics.sensors.fingerprint.Udfps;
 import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
 
 import java.util.function.Supplier;
 
-class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps {
+class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps,
+        PowerPressHandler {
 
     private static final String TAG = "FingerprintEnrollClient";
 
@@ -266,4 +268,10 @@
             Slog.e(TAG, "Unable to send UI ready", e);
         }
     }
+
+    @Override
+    public void onPowerPressed() {
+        onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
+                0 /* vendorCode */);
+    }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 23183f9..ab553a8 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -17,122 +17,33 @@
 package com.android.server.broadcastradio;
 
 import android.Manifest;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.hardware.radio.IAnnouncementListener;
-import android.hardware.radio.ICloseHandle;
 import android.hardware.radio.IRadioService;
-import android.hardware.radio.ITuner;
-import android.hardware.radio.ITunerCallback;
-import android.hardware.radio.RadioManager;
-import android.os.RemoteException;
-import android.util.IndentingPrintWriter;
 import android.util.Slog;
 
 import com.android.server.SystemService;
-import com.android.server.broadcastradio.hal2.AnnouncementAggregator;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.OptionalInt;
 
 public class BroadcastRadioService extends SystemService {
     private static final String TAG = "BcRadioSrv";
-
-    private final ServiceImpl mServiceImpl = new ServiceImpl();
-
-    private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1;
-    private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2;
-
-    private final Object mLock = new Object();
-    private final List<RadioManager.ModuleProperties> mV1Modules;
-
+    private final IRadioService mServiceImpl;
     public BroadcastRadioService(Context context) {
         super(context);
-
-        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock);
-        mV1Modules = mHal1.loadModules();
-        OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
-        mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
-                max.isPresent() ? max.getAsInt() + 1 : 0, mLock);
+        mServiceImpl = new BroadcastRadioServiceHidl(this);
     }
 
     @Override
     public void onStart() {
-        publishBinderService(Context.RADIO_SERVICE, mServiceImpl);
+        Slog.v(TAG, "BroadcastRadioService onStart()");
+        publishBinderService(Context.RADIO_SERVICE, mServiceImpl.asBinder());
     }
 
-    private class ServiceImpl extends IRadioService.Stub {
-        private void enforcePolicyAccess() {
-            if (PackageManager.PERMISSION_GRANTED != getContext().checkCallingPermission(
-                    Manifest.permission.ACCESS_BROADCAST_RADIO)) {
-                throw new SecurityException("ACCESS_BROADCAST_RADIO permission not granted");
-            }
-        }
-
-        @Override
-        public List<RadioManager.ModuleProperties> listModules() {
-            Slog.v(TAG, "Listing HIDL modules");
-            enforcePolicyAccess();
-            List<RadioManager.ModuleProperties> modules = new ArrayList<>();
-            modules.addAll(mV1Modules);
-            modules.addAll(mHal2.listModules());
-            return modules;
-        }
-
-        @Override
-        public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
-                boolean withAudio, ITunerCallback callback) throws RemoteException {
-            Slog.v(TAG, "Opening module " + moduleId);
-            enforcePolicyAccess();
-            if (callback == null) {
-                throw new IllegalArgumentException("Callback must not be empty");
-            }
-            synchronized (mLock) {
-                if (mHal2.hasModule(moduleId)) {
-                    return mHal2.openSession(moduleId, bandConfig, withAudio, callback);
-                } else {
-                    return mHal1.openTuner(moduleId, bandConfig, withAudio, callback);
-                }
-            }
-        }
-
-        @Override
-        public ICloseHandle addAnnouncementListener(int[] enabledTypes,
-                IAnnouncementListener listener) {
-            Slog.v(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes));
-            Objects.requireNonNull(enabledTypes);
-            Objects.requireNonNull(listener);
-            enforcePolicyAccess();
-
-            synchronized (mLock) {
-                if (!mHal2.hasAnyModules()) {
-                    Slog.i(TAG, "There are no HAL 2.0 modules registered");
-                    return new AnnouncementAggregator(listener, mLock);
-                }
-
-                return mHal2.addAnnouncementListener(enabledTypes, listener);
-            }
-        }
-
-        @Override
-        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            IndentingPrintWriter radioPw = new IndentingPrintWriter(pw);
-            radioPw.printf("BroadcastRadioService\n");
-            radioPw.increaseIndent();
-            radioPw.printf("HAL1: %s\n", mHal1);
-            radioPw.increaseIndent();
-            radioPw.printf("Modules of HAL1: %s\n", mV1Modules);
-            radioPw.decreaseIndent();
-            radioPw.printf("HAL2:\n");
-            radioPw.increaseIndent();
-            mHal2.dumpInfo(radioPw);
-            radioPw.decreaseIndent();
-            radioPw.decreaseIndent();
+    @SuppressLint("AndroidFrameworkRequiresPermission")
+    void enforcePolicyAccess() {
+        if (getContext().checkCallingPermission(Manifest.permission.ACCESS_BROADCAST_RADIO)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("ACCESS_BROADCAST_RADIO permission not granted");
         }
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioServiceHidl.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioServiceHidl.java
new file mode 100644
index 0000000..5cb6770
--- /dev/null
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioServiceHidl.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.broadcastradio;
+
+import android.hardware.radio.IAnnouncementListener;
+import android.hardware.radio.ICloseHandle;
+import android.hardware.radio.IRadioService;
+import android.hardware.radio.ITuner;
+import android.hardware.radio.ITunerCallback;
+import android.hardware.radio.RadioManager;
+import android.os.RemoteException;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.broadcastradio.hal2.AnnouncementAggregator;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.OptionalInt;
+
+/**
+ * Wrapper for HIDL interface for BroadcastRadio HAL
+ */
+final class BroadcastRadioServiceHidl extends IRadioService.Stub {
+    private static final String TAG = "BcRadioSrvHidl";
+
+    private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1;
+    private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2;
+
+    private final Object mLock = new Object();
+
+    private final BroadcastRadioService mService;
+    private final List<RadioManager.ModuleProperties> mV1Modules;
+
+    BroadcastRadioServiceHidl(BroadcastRadioService service) {
+        mService = Objects.requireNonNull(service);
+        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock);
+        mV1Modules = mHal1.loadModules();
+        OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
+        mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
+                max.isPresent() ? max.getAsInt() + 1 : 0, mLock);
+    }
+
+    @Override
+    public List<RadioManager.ModuleProperties> listModules() {
+        mService.enforcePolicyAccess();
+        Collection<RadioManager.ModuleProperties> v2Modules = mHal2.listModules();
+        List<RadioManager.ModuleProperties> modules = new ArrayList<>(
+                mV1Modules.size() + v2Modules.size());
+        modules.addAll(mV1Modules);
+        modules.addAll(v2Modules);
+        return modules;
+    }
+
+    @Override
+    public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
+            boolean withAudio, ITunerCallback callback) throws RemoteException {
+        if (isDebugEnabled()) {
+            Slog.d(TAG, "Opening module " + moduleId);
+        }
+        mService.enforcePolicyAccess();
+        Objects.requireNonNull(callback, "Callback must not be null");
+        synchronized (mLock) {
+            if (mHal2.hasModule(moduleId)) {
+                return mHal2.openSession(moduleId, bandConfig, withAudio, callback);
+            } else {
+                return mHal1.openTuner(moduleId, bandConfig, withAudio, callback);
+            }
+        }
+    }
+
+    @Override
+    public ICloseHandle addAnnouncementListener(int[] enabledTypes,
+            IAnnouncementListener listener) {
+        if (isDebugEnabled()) {
+            Slog.d(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes));
+        }
+        Objects.requireNonNull(enabledTypes);
+        Objects.requireNonNull(listener);
+        mService.enforcePolicyAccess();
+
+        synchronized (mLock) {
+            if (!mHal2.hasAnyModules()) {
+                Slog.w(TAG, "There are no HAL 2.0 modules registered");
+                return new AnnouncementAggregator(listener, mLock);
+            }
+
+            return mHal2.addAnnouncementListener(enabledTypes, listener);
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        IndentingPrintWriter radioPw = new IndentingPrintWriter(pw);
+        radioPw.printf("BroadcastRadioService\n");
+
+        radioPw.increaseIndent();
+        radioPw.printf("HAL1: %s\n", mHal1);
+
+        radioPw.increaseIndent();
+        radioPw.printf("Modules of HAL1: %s\n", mV1Modules);
+        radioPw.decreaseIndent();
+
+        radioPw.printf("HAL2:\n");
+
+        radioPw.increaseIndent();
+        mHal2.dumpInfo(radioPw);
+        radioPw.decreaseIndent();
+
+        radioPw.decreaseIndent();
+    }
+
+
+    private static boolean isDebugEnabled() {
+        return Log.isLoggable(TAG, Log.DEBUG);
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 9cb1f1d..676dc19 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -99,6 +99,7 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.FileUtils;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Looper;
@@ -1198,7 +1199,7 @@
                 mContext.unbindService(mConnection);
                 cleanupVpnStateLocked();
             } else if (mVpnRunner != null) {
-                stopVpnRunnerAndNotifyAppLocked(mPackage);
+                stopVpnRunnerAndNotifyAppLocked();
             }
 
             try {
@@ -2784,26 +2785,18 @@
             // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
             // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
             // this is considered safe.
-            final NetworkRequest req;
 
             if (mProfile.isRestrictedToTestNetworks()) {
-                req = new NetworkRequest.Builder()
+                final NetworkRequest req = new NetworkRequest.Builder()
                         .clearCapabilities()
                         .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
                         .addCapability(NET_CAPABILITY_NOT_VPN)
                         .build();
+                mConnectivityManager.requestNetwork(req, mNetworkCallback);
             } else {
-                // Basically, the request here is referring to the default request which is defined
-                // in ConnectivityService. Ideally, ConnectivityManager should provide an new API
-                // which can provide the status of physical network even though there is a virtual
-                // network. b/147280869 is used for tracking the new API.
-                // TODO: Use the new API to register default physical network.
-                req = new NetworkRequest.Builder()
-                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build();
+                mConnectivityManager.registerSystemDefaultNetworkCallback(mNetworkCallback,
+                        new Handler(mLooper));
             }
-
-            mConnectivityManager.requestNetwork(req, mNetworkCallback);
         }
 
         private boolean isActiveNetwork(@Nullable Network network) {
@@ -4061,7 +4054,7 @@
     }
 
     @GuardedBy("this")
-    private void stopVpnRunnerAndNotifyAppLocked(@NonNull String packageName) {
+    private void stopVpnRunnerAndNotifyAppLocked() {
         // Build intent first because the sessionKey will be reset after performing
         // VpnRunner.exit(). Also, cache mOwnerUID even if ownerUID will not be changed in
         // VpnRunner.exit() to prevent design being changed in the future.
@@ -4069,17 +4062,17 @@
         //  ConnectivityServiceTest.
         final int ownerUid = mOwnerUID;
         Intent intent = null;
-        if (SdkLevel.isAtLeastT() && isVpnApp(packageName)) {
+        if (SdkLevel.isAtLeastT() && isVpnApp(mPackage)) {
             intent = buildVpnManagerEventIntent(
                     VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
-                    -1 /* errorClass */, -1 /* errorCode*/, packageName,
+                    -1 /* errorClass */, -1 /* errorCode*/, mPackage,
                     getSessionKeyLocked(), makeVpnProfileStateLocked(),
                     null /* underlyingNetwork */, null /* nc */, null /* lp */);
         }
         // cleanupVpnStateLocked() is called from mVpnRunner.exit()
         mVpnRunner.exit();
-        if (intent != null && isVpnApp(packageName)) {
-            notifyVpnManagerVpnStopped(packageName, ownerUid, intent);
+        if (intent != null && isVpnApp(mPackage)) {
+            notifyVpnManagerVpnStopped(mPackage, ownerUid, intent);
         }
     }
 
@@ -4099,7 +4092,7 @@
         // To stop the VPN profile, the caller must be the current prepared package and must be
         // running an Ikev2VpnProfile.
         if (isCurrentIkev2VpnLocked(packageName)) {
-            stopVpnRunnerAndNotifyAppLocked(packageName);
+            stopVpnRunnerAndNotifyAppLocked();
         }
     }
 
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 6145a91c..b3aee22 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -131,6 +131,8 @@
     // Configuration object for determining thresholds to change brightness dynamically
     private final HysteresisLevels mAmbientBrightnessThresholds;
     private final HysteresisLevels mScreenBrightnessThresholds;
+    private final HysteresisLevels mAmbientBrightnessThresholdsIdle;
+    private final HysteresisLevels mScreenBrightnessThresholdsIdle;
 
     private boolean mLoggingEnabled;
 
@@ -242,7 +244,9 @@
             float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
             long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
             boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
-            HysteresisLevels screenBrightnessThresholds, Context context,
+            HysteresisLevels screenBrightnessThresholds,
+            HysteresisLevels ambientBrightnessThresholdsIdle,
+            HysteresisLevels screenBrightnessThresholdsIdle, Context context,
             HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
             BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
             int ambientLightHorizonLong) {
@@ -251,7 +255,8 @@
                 lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
                 lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
                 darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
-                ambientBrightnessThresholds, screenBrightnessThresholds, context,
+                ambientBrightnessThresholds, screenBrightnessThresholds,
+                ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, context,
                 hbmController, brightnessThrottler, idleModeBrightnessMapper,
                 ambientLightHorizonShort, ambientLightHorizonLong
         );
@@ -265,7 +270,9 @@
             float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
             long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
             boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
-            HysteresisLevels screenBrightnessThresholds, Context context,
+            HysteresisLevels screenBrightnessThresholds,
+            HysteresisLevels ambientBrightnessThresholdsIdle,
+            HysteresisLevels screenBrightnessThresholdsIdle, Context context,
             HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
             BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
             int ambientLightHorizonLong) {
@@ -289,7 +296,9 @@
         mAmbientLightHorizonShort = ambientLightHorizonShort;
         mWeightingIntercept = ambientLightHorizonLong;
         mAmbientBrightnessThresholds = ambientBrightnessThresholds;
+        mAmbientBrightnessThresholdsIdle = ambientBrightnessThresholdsIdle;
         mScreenBrightnessThresholds = screenBrightnessThresholds;
+        mScreenBrightnessThresholdsIdle = screenBrightnessThresholdsIdle;
         mShortTermModelValid = true;
         mShortTermModelAnchor = -1;
         mHandler = new AutomaticBrightnessHandler(looper);
@@ -586,6 +595,8 @@
         pw.println();
         mAmbientBrightnessThresholds.dump(pw);
         mScreenBrightnessThresholds.dump(pw);
+        mScreenBrightnessThresholdsIdle.dump(pw);
+        mScreenBrightnessThresholdsIdle.dump(pw);
     }
 
     private String configStateToString(int state) {
@@ -680,8 +691,17 @@
             lux = 0;
         }
         mAmbientLux = lux;
-        mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
-        mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
+        if (isInIdleMode()) {
+            mAmbientBrighteningThreshold =
+                    mAmbientBrightnessThresholdsIdle.getBrighteningThreshold(lux);
+            mAmbientDarkeningThreshold =
+                    mAmbientBrightnessThresholdsIdle.getDarkeningThreshold(lux);
+        } else {
+            mAmbientBrighteningThreshold =
+                    mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
+            mAmbientDarkeningThreshold =
+                    mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
+        }
         mHbmController.onAmbientLuxChange(mAmbientLux);
 
         // If the short term model was invalidated and the change is drastic enough, reset it.
@@ -903,10 +923,20 @@
                 mPreThresholdBrightness = mScreenAutoBrightness;
             }
             mScreenAutoBrightness = newScreenAutoBrightness;
-            mScreenBrighteningThreshold = clampScreenBrightness(
-                    mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
-            mScreenDarkeningThreshold = clampScreenBrightness(
-                    mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
+            if (isInIdleMode()) {
+                mScreenBrighteningThreshold = clampScreenBrightness(
+                        mScreenBrightnessThresholdsIdle.getBrighteningThreshold(
+                                newScreenAutoBrightness));
+                mScreenDarkeningThreshold = clampScreenBrightness(
+                        mScreenBrightnessThresholdsIdle.getDarkeningThreshold(
+                                newScreenAutoBrightness));
+            } else {
+                mScreenBrighteningThreshold = clampScreenBrightness(
+                        mScreenBrightnessThresholds.getBrighteningThreshold(
+                                newScreenAutoBrightness));
+                mScreenDarkeningThreshold = clampScreenBrightness(
+                        mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
+            }
 
             if (sendUpdate) {
                 mCallbacks.updateBrightness();
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index cb04ddf..2f67ddd 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -39,6 +39,7 @@
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
+import android.window.ScreenCapture;
 
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
@@ -181,7 +182,7 @@
         // Set mPrepared here so if initialization fails, resources can be cleaned up.
         mPrepared = true;
 
-        final SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
+        final ScreenCapture.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
         if (hardwareBuffer == null) {
             dismiss();
             return false;
@@ -508,7 +509,7 @@
     }
 
     private boolean setScreenshotTextureAndSetViewport(
-            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
+            ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer) {
         if (!attachEglContext()) {
             return false;
         }
@@ -559,8 +560,8 @@
         }
     }
 
-    private SurfaceControl.ScreenshotHardwareBuffer captureScreen() {
-        SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+    private ScreenCapture.ScreenshotHardwareBuffer captureScreen() {
+        ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
                 mDisplayManagerInternal.systemScreenshot(mDisplayId);
         if (screenshotBuffer == null) {
             Slog.e(TAG, "Failed to take screenshot. Buffer is null");
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 12b2f47..4165186 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -188,8 +188,8 @@
  *      <ambientLightHorizonLong>10001</ambientLightHorizonLong>
  *      <ambientLightHorizonShort>2001</ambientLightHorizonShort>
  *
- *      <displayBrightnessChangeThresholds>
- *        <brighteningThresholds>
+ *      <displayBrightnessChangeThresholds> // Thresholds for screen changes
+ *        <brighteningThresholds>     // Thresholds for active mode brightness changes.
  *          <minimum>0.001</minimum>  // Minimum change needed in screen brightness to brighten.
  *        </brighteningThresholds>
  *        <darkeningThresholds>
@@ -197,8 +197,8 @@
  *        </darkeningThresholds>
  *      </displayBrightnessChangeThresholds>
  *
- *      <ambientBrightnessChangeThresholds>
- *        <brighteningThresholds>
+ *      <ambientBrightnessChangeThresholds> // Thresholds for lux changes
+ *        <brighteningThresholds>     // Thresholds for active mode brightness changes.
  *          <minimum>0.003</minimum>  // Minimum change needed in ambient brightness to brighten.
  *        </brighteningThresholds>
  *        <darkeningThresholds>
@@ -206,6 +206,24 @@
  *        </darkeningThresholds>
  *      </ambientBrightnessChangeThresholds>
  *
+ *      <displayBrightnessChangeThresholdsIdle> // Thresholds for screen changes in idle mode
+ *        <brighteningThresholds>     // Thresholds for idle mode brightness changes.
+ *          <minimum>0.001</minimum>  // Minimum change needed in screen brightness to brighten.
+ *        </brighteningThresholds>
+ *        <darkeningThresholds>
+ *          <minimum>0.002</minimum>  // Minimum change needed in screen brightness to darken.
+ *        </darkeningThresholds>
+ *      </displayBrightnessChangeThresholdsIdle>
+ *
+ *      <ambientBrightnessChangeThresholdsIdle> // Thresholds for lux changes in idle mode
+ *        <brighteningThresholds>     // Thresholds for idle mode brightness changes.
+ *          <minimum>0.003</minimum>  // Minimum change needed in ambient brightness to brighten.
+ *        </brighteningThresholds>
+ *        <darkeningThresholds>
+ *          <minimum>0.004</minimum>  // Minimum change needed in ambient brightness to darken.
+ *        </darkeningThresholds>
+ *      </ambientBrightnessChangeThresholdsIdle>
+ *
  *    </displayConfiguration>
  *  }
  *  </pre>
@@ -319,9 +337,13 @@
     private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
     private int mAmbientHorizonShort = AMBIENT_LIGHT_SHORT_HORIZON_MILLIS;
     private float mScreenBrighteningMinThreshold = 0.0f;     // Retain behaviour as though there is
-    private float mScreenDarkeningMinThreshold = 0.0f;       // no minimum threshold for change in
-    private float mAmbientLuxBrighteningMinThreshold = 0.0f; // screen brightness or ambient
-    private float mAmbientLuxDarkeningMinThreshold = 0.0f;   // brightness.
+    private float mScreenBrighteningMinThresholdIdle = 0.0f; // no minimum threshold for change in
+    private float mScreenDarkeningMinThreshold = 0.0f;       // screen brightness or ambient
+    private float mScreenDarkeningMinThresholdIdle = 0.0f;   // brightness.
+    private float mAmbientLuxBrighteningMinThreshold = 0.0f;
+    private float mAmbientLuxBrighteningMinThresholdIdle = 0.0f;
+    private float mAmbientLuxDarkeningMinThreshold = 0.0f;
+    private float mAmbientLuxDarkeningMinThresholdIdle = 0.0f;
     private Spline mBrightnessToBacklightSpline;
     private Spline mBacklightToBrightnessSpline;
     private Spline mBacklightToNitsSpline;
@@ -625,22 +647,76 @@
         return mAmbientHorizonShort;
     }
 
+    /**
+     * The minimum value for the screen brightness increase to actually occur.
+     * @return float value in brightness scale of 0 - 1.
+     */
     public float getScreenBrighteningMinThreshold() {
         return mScreenBrighteningMinThreshold;
     }
 
+    /**
+     * The minimum value for the screen brightness decrease to actually occur.
+     * @return float value in brightness scale of 0 - 1.
+     */
     public float getScreenDarkeningMinThreshold() {
         return mScreenDarkeningMinThreshold;
     }
 
+    /**
+     * The minimum value for the screen brightness increase to actually occur while in idle screen
+     * brightness mode.
+     * @return float value in brightness scale of 0 - 1.
+     */
+    public float getScreenBrighteningMinThresholdIdle() {
+        return mScreenBrighteningMinThresholdIdle;
+    }
+
+    /**
+     * The minimum value for the screen brightness decrease to actually occur while in idle screen
+     * brightness mode.
+     * @return float value in brightness scale of 0 - 1.
+     */
+    public float getScreenDarkeningMinThresholdIdle() {
+        return mScreenDarkeningMinThresholdIdle;
+    }
+
+    /**
+     * The minimum value for the ambient lux increase for a screen brightness change to actually
+     * occur.
+     * @return float value in brightness scale of 0 - 1.
+     */
     public float getAmbientLuxBrighteningMinThreshold() {
         return mAmbientLuxBrighteningMinThreshold;
     }
 
+    /**
+     * The minimum value for the ambient lux decrease for a screen brightness change to actually
+     * occur.
+     * @return float value in brightness scale of 0 - 1.
+     */
     public float getAmbientLuxDarkeningMinThreshold() {
         return mAmbientLuxDarkeningMinThreshold;
     }
 
+    /**
+     * The minimum value for the ambient lux increase for a screen brightness change to actually
+     * occur while in idle screen brightness mode.
+     * @return float value in brightness scale of 0 - 1.
+     */
+    public float getAmbientLuxBrighteningMinThresholdIdle() {
+        return mAmbientLuxBrighteningMinThresholdIdle;
+    }
+
+    /**
+     * The minimum value for the ambient lux decrease for a screen brightness change to actually
+     * occur while in idle screen brightness mode.
+     * @return float value in brightness scale of 0 - 1.
+     */
+    public float getAmbientLuxDarkeningMinThresholdIdle() {
+        return mAmbientLuxDarkeningMinThresholdIdle;
+    }
+
     SensorData getAmbientLightSensor() {
         return mAmbientLightSensor;
     }
@@ -745,9 +821,14 @@
                 + ", mAmbientHorizonLong=" + mAmbientHorizonLong
                 + ", mAmbientHorizonShort=" + mAmbientHorizonShort
                 + ", mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
+                + ", mScreenDarkeningMinThresholdIdle=" + mScreenDarkeningMinThresholdIdle
                 + ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold
+                + ", mScreenBrighteningMinThresholdIdle=" + mScreenBrighteningMinThresholdIdle
                 + ", mAmbientLuxDarkeningMinThreshold=" + mAmbientLuxDarkeningMinThreshold
+                + ", mAmbientLuxDarkeningMinThresholdIdle=" + mAmbientLuxDarkeningMinThresholdIdle
                 + ", mAmbientLuxBrighteningMinThreshold=" + mAmbientLuxBrighteningMinThreshold
+                + ", mAmbientLuxBrighteningMinThresholdIdle="
+                + mAmbientLuxBrighteningMinThresholdIdle
                 + ", mAmbientLightSensor=" + mAmbientLightSensor
                 + ", mProximitySensor=" + mProximitySensor
                 + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
@@ -1376,24 +1457,34 @@
     private void loadBrightnessChangeThresholds(DisplayConfiguration config) {
         Thresholds displayBrightnessThresholds = config.getDisplayBrightnessChangeThresholds();
         Thresholds ambientBrightnessThresholds = config.getAmbientBrightnessChangeThresholds();
+        Thresholds displayBrightnessThresholdsIdle =
+                config.getDisplayBrightnessChangeThresholdsIdle();
+        Thresholds ambientBrightnessThresholdsIdle =
+                config.getAmbientBrightnessChangeThresholdsIdle();
 
+        loadDisplayBrightnessThresholds(displayBrightnessThresholds);
+        loadAmbientBrightnessThresholds(ambientBrightnessThresholds);
+        loadIdleDisplayBrightnessThresholds(displayBrightnessThresholdsIdle);
+        loadIdleAmbientBrightnessThresholds(ambientBrightnessThresholdsIdle);
+    }
+
+    private void loadDisplayBrightnessThresholds(Thresholds displayBrightnessThresholds) {
         if (displayBrightnessThresholds != null) {
             BrightnessThresholds brighteningScreen =
                     displayBrightnessThresholds.getBrighteningThresholds();
             BrightnessThresholds darkeningScreen =
                     displayBrightnessThresholds.getDarkeningThresholds();
 
-            final BigDecimal screenBrighteningThreshold = brighteningScreen.getMinimum();
-            final BigDecimal screenDarkeningThreshold = darkeningScreen.getMinimum();
-
-            if (screenBrighteningThreshold != null) {
-                mScreenBrighteningMinThreshold = screenBrighteningThreshold.floatValue();
+            if (brighteningScreen != null && brighteningScreen.getMinimum() != null) {
+                mScreenBrighteningMinThreshold = brighteningScreen.getMinimum().floatValue();
             }
-            if (screenDarkeningThreshold != null) {
-                mScreenDarkeningMinThreshold = screenDarkeningThreshold.floatValue();
+            if (darkeningScreen != null && darkeningScreen.getMinimum() != null) {
+                mScreenDarkeningMinThreshold = darkeningScreen.getMinimum().floatValue();
             }
         }
+    }
 
+    private void loadAmbientBrightnessThresholds(Thresholds ambientBrightnessThresholds) {
         if (ambientBrightnessThresholds != null) {
             BrightnessThresholds brighteningAmbientLux =
                     ambientBrightnessThresholds.getBrighteningThresholds();
@@ -1412,6 +1503,44 @@
         }
     }
 
+    private void loadIdleDisplayBrightnessThresholds(Thresholds idleDisplayBrightnessThresholds) {
+        if (idleDisplayBrightnessThresholds != null) {
+            BrightnessThresholds brighteningScreenIdle =
+                    idleDisplayBrightnessThresholds.getBrighteningThresholds();
+            BrightnessThresholds darkeningScreenIdle =
+                    idleDisplayBrightnessThresholds.getDarkeningThresholds();
+
+            if (brighteningScreenIdle != null
+                    && brighteningScreenIdle.getMinimum() != null) {
+                mScreenBrighteningMinThresholdIdle =
+                        brighteningScreenIdle.getMinimum().floatValue();
+            }
+            if (darkeningScreenIdle != null && darkeningScreenIdle.getMinimum() != null) {
+                mScreenDarkeningMinThresholdIdle =
+                        darkeningScreenIdle.getMinimum().floatValue();
+            }
+        }
+    }
+
+    private void loadIdleAmbientBrightnessThresholds(Thresholds idleAmbientBrightnessThresholds) {
+        if (idleAmbientBrightnessThresholds != null) {
+            BrightnessThresholds brighteningAmbientLuxIdle =
+                    idleAmbientBrightnessThresholds.getBrighteningThresholds();
+            BrightnessThresholds darkeningAmbientLuxIdle =
+                    idleAmbientBrightnessThresholds.getDarkeningThresholds();
+
+            if (brighteningAmbientLuxIdle != null
+                    && brighteningAmbientLuxIdle.getMinimum() != null) {
+                mAmbientLuxBrighteningMinThresholdIdle =
+                        brighteningAmbientLuxIdle.getMinimum().floatValue();
+            }
+            if (darkeningAmbientLuxIdle != null && darkeningAmbientLuxIdle.getMinimum() != null) {
+                mAmbientLuxDarkeningMinThresholdIdle =
+                        darkeningAmbientLuxIdle.getMinimum().floatValue();
+            }
+        }
+    }
+
     private boolean thermalStatusIsValid(ThermalStatus value) {
         if (value == null) {
             return false;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e53ac37..3a037ed 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -35,6 +35,7 @@
 import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;
 import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;
 import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL;
+import static android.os.Process.ROOT_UID;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -118,6 +119,7 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.window.DisplayWindowPolicyController;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -200,6 +202,8 @@
     private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
 
     private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
+    private static final String PROP_USE_NEW_DISPLAY_POWER_CONTROLLER =
+            "persist.sys.use_new_display_power_controller";
     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
     // This value needs to be in sync with the threshold
     // in RefreshRateConfigs::getFrameRateDivisor.
@@ -274,7 +278,7 @@
             new CopyOnWriteArrayList<>();
 
     /** All {@link DisplayPowerController}s indexed by {@link LogicalDisplay} ID. */
-    private final SparseArray<DisplayPowerController> mDisplayPowerControllers =
+    private final SparseArray<DisplayPowerControllerInterface> mDisplayPowerControllers =
             new SparseArray<>();
 
     /** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
@@ -497,7 +501,6 @@
         ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
         mWideColorSpace = colorSpaces[1];
         mAllowNonNativeRefreshRateOverride = mInjector.getAllowNonNativeRefreshRateOverride();
-
         mSystemReady = false;
     }
 
@@ -577,7 +580,7 @@
                 if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
                     return;
                 }
-                final DisplayPowerController dpc = mDisplayPowerControllers.get(
+                final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(
                         logicalDisplay.getDisplayIdLocked());
                 if (dpc == null) {
                     return;
@@ -1170,6 +1173,10 @@
     }
 
     private boolean validatePackageName(int uid, String packageName) {
+        // Root doesn't have a package name.
+        if (uid == ROOT_UID) {
+            return true;
+        }
         if (packageName != null) {
             String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
             if (packageNames != null) {
@@ -1557,7 +1564,7 @@
         scheduleTraversalLocked(false);
         mPersistentDataStore.saveIfNeeded();
 
-        DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+        DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
             dpc.onDisplayChanged();
         }
@@ -1575,7 +1582,8 @@
 
     private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
         final int displayId = display.getDisplayIdLocked();
-        final DisplayPowerController dpc = mDisplayPowerControllers.removeReturnOld(displayId);
+        final DisplayPowerControllerInterface dpc =
+                mDisplayPowerControllers.removeReturnOld(displayId);
         if (dpc != null) {
             dpc.stop();
         }
@@ -1604,7 +1612,7 @@
             mHandler.post(work);
         }
         final int displayId = display.getDisplayIdLocked();
-        DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+        DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
             dpc.onDisplayChanged();
         }
@@ -1615,7 +1623,7 @@
 
     private void handleLogicalDisplayDeviceStateTransitionLocked(@NonNull LogicalDisplay display) {
         final int displayId = display.getDisplayIdLocked();
-        final DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+        final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
             dpc.onDeviceStateTransition();
         }
@@ -1852,14 +1860,14 @@
             if (userId != mCurrentUserId) {
                 return;
             }
-            DisplayPowerController dpc = getDpcFromUniqueIdLocked(uniqueId);
+            DisplayPowerControllerInterface dpc = getDpcFromUniqueIdLocked(uniqueId);
             if (dpc != null) {
                 dpc.setBrightnessConfiguration(c);
             }
         }
     }
 
-    private DisplayPowerController getDpcFromUniqueIdLocked(String uniqueId) {
+    private DisplayPowerControllerInterface getDpcFromUniqueIdLocked(String uniqueId) {
         final DisplayDevice displayDevice = mDisplayDeviceRepo.getByUniqueIdLocked(uniqueId);
         final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayDevice);
         if (logicalDisplay != null) {
@@ -1900,7 +1908,7 @@
                 final BrightnessConfiguration config =
                         getBrightnessConfigForDisplayWithPdsFallbackLocked(uniqueId, userSerial);
                 if (config != null) {
-                    final DisplayPowerController dpc = mDisplayPowerControllers.get(
+                    final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(
                             logicalDisplay.getDisplayIdLocked());
                     if (dpc != null) {
                         dpc.setBrightnessConfiguration(config);
@@ -2049,8 +2057,8 @@
         return null;
     }
 
-    private SurfaceControl.ScreenshotHardwareBuffer systemScreenshotInternal(int displayId) {
-        final SurfaceControl.DisplayCaptureArgs captureArgs;
+    private ScreenCapture.ScreenshotHardwareBuffer systemScreenshotInternal(int displayId) {
+        final ScreenCapture.DisplayCaptureArgs captureArgs;
         synchronized (mSyncRoot) {
             final IBinder token = getDisplayToken(displayId);
             if (token == null) {
@@ -2062,27 +2070,27 @@
             }
 
             final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
-            captureArgs = new SurfaceControl.DisplayCaptureArgs.Builder(token)
+            captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
                     .setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight())
                     .setUseIdentityTransform(true)
                     .setCaptureSecureLayers(true)
                     .setAllowProtected(true)
                     .build();
         }
-        return SurfaceControl.captureDisplay(captureArgs);
+        return ScreenCapture.captureDisplay(captureArgs);
     }
 
-    private SurfaceControl.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
+    private ScreenCapture.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
         synchronized (mSyncRoot) {
             final IBinder token = getDisplayToken(displayId);
             if (token == null) {
                 return null;
             }
 
-            final SurfaceControl.DisplayCaptureArgs captureArgs =
-                    new SurfaceControl.DisplayCaptureArgs.Builder(token)
+            final ScreenCapture.DisplayCaptureArgs captureArgs =
+                    new ScreenCapture.DisplayCaptureArgs.Builder(token)
                             .build();
-            return SurfaceControl.captureDisplay(captureArgs);
+            return ScreenCapture.captureDisplay(captureArgs);
         }
     }
 
@@ -2132,8 +2140,8 @@
 
     void setAutoBrightnessLoggingEnabled(boolean enabled) {
         synchronized (mSyncRoot) {
-            final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
-                    Display.DEFAULT_DISPLAY);
+            final DisplayPowerControllerInterface displayPowerController =
+                    mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
             if (displayPowerController != null) {
                 displayPowerController.setAutoBrightnessLoggingEnabled(enabled);
             }
@@ -2142,8 +2150,8 @@
 
     void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
         synchronized (mSyncRoot) {
-            final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
-                    Display.DEFAULT_DISPLAY);
+            final DisplayPowerControllerInterface displayPowerController =
+                    mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
             if (displayPowerController != null) {
                 displayPowerController.setDisplayWhiteBalanceLoggingEnabled(enabled);
             }
@@ -2170,8 +2178,8 @@
 
     void setAmbientColorTemperatureOverride(float cct) {
         synchronized (mSyncRoot) {
-            final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
-                    Display.DEFAULT_DISPLAY);
+            final DisplayPowerControllerInterface displayPowerController =
+                    mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY);
             if (displayPowerController != null) {
                 displayPowerController.setAmbientColorTemperatureOverride(cct);
             }
@@ -2180,8 +2188,8 @@
 
     void setDockedAndIdleEnabled(boolean enabled, int displayId) {
         synchronized (mSyncRoot) {
-            final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
-                    displayId);
+            final DisplayPowerControllerInterface displayPowerController =
+                    mDisplayPowerControllers.get(displayId);
             if (displayPowerController != null) {
                 displayPowerController.setAutomaticScreenBrightnessMode(enabled);
             }
@@ -2554,10 +2562,19 @@
 
         final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore,
                 display, mSyncRoot);
-        final DisplayPowerController displayPowerController = new DisplayPowerController(
-                mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
-                mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
-                () -> handleBrightnessChange(display));
+        final DisplayPowerController displayPowerController;
+
+        if (SystemProperties.getInt(PROP_USE_NEW_DISPLAY_POWER_CONTROLLER, 0) == 1) {
+            displayPowerController = new DisplayPowerController(
+                    mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
+                    mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
+                    () -> handleBrightnessChange(display));
+        } else {
+            displayPowerController = new DisplayPowerController(
+                    mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
+                    mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
+                    () -> handleBrightnessChange(display));
+        }
         mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
     }
 
@@ -3212,7 +3229,7 @@
                                     uniqueId, userSerial);
                     if (config == null) {
                         // Get default configuration
-                        DisplayPowerController dpc = getDpcFromUniqueIdLocked(uniqueId);
+                        DisplayPowerControllerInterface dpc = getDpcFromUniqueIdLocked(uniqueId);
                         if (dpc != null) {
                             config = dpc.getDefaultBrightnessConfiguration();
                         }
@@ -3263,7 +3280,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mSyncRoot) {
-                    DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+                    DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
                     if (dpc != null) {
                         return dpc.getBrightnessInfo();
                     }
@@ -3310,7 +3327,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mSyncRoot) {
-                    DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+                    DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
                     if (dpc != null) {
                         dpc.setBrightness(brightness);
                     }
@@ -3330,7 +3347,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mSyncRoot) {
-                    DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+                    DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
                     if (dpc != null) {
                         brightness = dpc.getScreenBrightnessSetting();
                     }
@@ -3476,6 +3493,17 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public void setDisplayIdToMirror(IBinder token, int displayId) {
+            synchronized (mSyncRoot) {
+                final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+                if (mVirtualDisplayAdapter != null) {
+                    mVirtualDisplayAdapter.setDisplayIdToMirror(token,
+                            display == null ? Display.INVALID_DISPLAY : displayId);
+                }
+            }
+        }
     }
 
     private static boolean isValidBrightness(float brightness) {
@@ -3534,7 +3562,7 @@
                             id).getPrimaryDisplayDeviceLocked();
                     final int flags = displayDevice.getDisplayDeviceInfoLocked().flags;
                     if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-                        final DisplayPowerController displayPowerController =
+                        final DisplayPowerControllerInterface displayPowerController =
                                 mDisplayPowerControllers.get(id);
                         ready &= displayPowerController.requestPowerState(request,
                                 waitForNegativeProximity);
@@ -3564,12 +3592,12 @@
         }
 
         @Override
-        public SurfaceControl.ScreenshotHardwareBuffer systemScreenshot(int displayId) {
+        public ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId) {
             return systemScreenshotInternal(displayId);
         }
 
         @Override
-        public SurfaceControl.ScreenshotHardwareBuffer userScreenshot(int displayId) {
+        public ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId) {
             return userScreenshotInternal(displayId);
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2476350..58a80e3 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -104,7 +104,7 @@
  * slower by changing the "animator duration scale" option in Development Settings.
  */
 final class DisplayPowerController implements AutomaticBrightnessController.Callbacks,
-        DisplayWhiteBalanceController.Callbacks {
+        DisplayWhiteBalanceController.Callbacks, DisplayPowerControllerInterface {
     private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
     private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked";
 
@@ -682,6 +682,7 @@
     /**
      * Returns true if the proximity sensor screen-off function is available.
      */
+    @Override
     public boolean isProximitySensorAvailable() {
         return mProximitySensor != null;
     }
@@ -693,6 +694,7 @@
      * @param includePackage if false will null out the package name in events
      */
     @Nullable
+    @Override
     public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(
             @UserIdInt int userId, boolean includePackage) {
         if (mBrightnessTracker == null) {
@@ -701,6 +703,7 @@
         return mBrightnessTracker.getEvents(userId, includePackage);
     }
 
+    @Override
     public void onSwitchUser(@UserIdInt int newUserId) {
         handleSettingsChange(true /* userSwitch */);
         if (mBrightnessTracker != null) {
@@ -709,6 +712,7 @@
     }
 
     @Nullable
+    @Override
     public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(
             @UserIdInt int userId) {
         if (mBrightnessTracker == null) {
@@ -720,6 +724,7 @@
     /**
      * Persist the brightness slider events and ambient brightness stats to disk.
      */
+    @Override
     public void persistBrightnessTrackerState() {
         if (mBrightnessTracker != null) {
             mBrightnessTracker.persistBrightnessTrackerState();
@@ -781,6 +786,7 @@
         }
     }
 
+    @Override
     public BrightnessConfiguration getDefaultBrightnessConfiguration() {
         if (mAutomaticBrightnessController == null) {
             return null;
@@ -794,6 +800,7 @@
      * of each display need to be properly reflected in AutomaticBrightnessController.
      */
     @GuardedBy("DisplayManagerService.mSyncRoot")
+    @Override
     public void onDisplayChanged() {
         final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
         if (device == null) {
@@ -823,6 +830,7 @@
      * This process involves turning off some displays so we need updatePowerState() to run and
      * calculate the new state.
      */
+    @Override
     public void onDeviceStateTransition() {
         sendUpdatePowerState();
     }
@@ -833,6 +841,7 @@
      * This method should be called when the DisplayPowerController is no longer in use; i.e. when
      * the {@link #mDisplayId display} has been removed.
      */
+    @Override
     public void stop() {
         synchronized (mLock) {
             mStopped = true;
@@ -989,6 +998,25 @@
                     screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
                     screenDarkeningMinThreshold, screenBrighteningMinThreshold);
 
+            // Idle screen thresholds
+            float screenDarkeningMinThresholdIdle =
+                    mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle();
+            float screenBrighteningMinThresholdIdle =
+                    mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle();
+            HysteresisLevels screenBrightnessThresholdsIdle = new HysteresisLevels(
+                    screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
+                    screenDarkeningMinThresholdIdle, screenBrighteningMinThresholdIdle);
+
+            // Idle ambient thresholds
+            float ambientDarkeningMinThresholdIdle =
+                    mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle();
+            float ambientBrighteningMinThresholdIdle =
+                    mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle();
+            HysteresisLevels ambientBrightnessThresholdsIdle = new HysteresisLevels(
+                    ambientBrighteningThresholds, ambientDarkeningThresholds,
+                    ambientThresholdLevels, ambientDarkeningMinThresholdIdle,
+                    ambientBrighteningMinThresholdIdle);
+
             long brighteningLightDebounce = mDisplayDeviceConfig
                     .getAutoBrightnessBrighteningLightDebounce();
             long darkeningLightDebounce = mDisplayDeviceConfig
@@ -1024,7 +1052,8 @@
                     PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor,
                     lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
                     darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
-                    ambientBrightnessThresholds, screenBrightnessThresholds, mContext,
+                    ambientBrightnessThresholds, screenBrightnessThresholds,
+                    ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext,
                     mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper,
                     mDisplayDeviceConfig.getAmbientHorizonShort(),
                     mDisplayDeviceConfig.getAmbientHorizonLong());
@@ -1063,6 +1092,7 @@
         }
     }
 
+    @Override
     public void setAutomaticScreenBrightnessMode(boolean isIdle) {
         if (mAutomaticBrightnessController != null) {
             if (isIdle) {
@@ -1766,27 +1796,32 @@
      * Ignores the proximity sensor until the sensor state changes, but only if the sensor is
      * currently enabled and forcing the screen to be dark.
      */
+    @Override
     public void ignoreProximitySensorUntilChanged() {
         mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY);
     }
 
+    @Override
     public void setBrightnessConfiguration(BrightnessConfiguration c) {
         Message msg = mHandler.obtainMessage(MSG_CONFIGURE_BRIGHTNESS, c);
         msg.sendToTarget();
     }
 
+    @Override
     public void setTemporaryBrightness(float brightness) {
         Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS,
                 Float.floatToIntBits(brightness), 0 /*unused*/);
         msg.sendToTarget();
     }
 
+    @Override
     public void setTemporaryAutoBrightnessAdjustment(float adjustment) {
         Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT,
                 Float.floatToIntBits(adjustment), 0 /*unused*/);
         msg.sendToTarget();
     }
 
+    @Override
     public BrightnessInfo getBrightnessInfo() {
         synchronized (mCachedBrightnessInfo) {
             return new BrightnessInfo(
@@ -2347,7 +2382,8 @@
         return Float.isNaN(adj) ? 0.0f : clampAutoBrightnessAdjustment(adj);
     }
 
-    float getScreenBrightnessSetting() {
+    @Override
+    public float getScreenBrightnessSetting() {
         float brightness = mBrightnessSetting.getBrightness();
         if (Float.isNaN(brightness)) {
             brightness = mScreenBrightnessDefault;
@@ -2362,7 +2398,8 @@
         return clampScreenBrightnessForVr(brightnessFloat);
     }
 
-    void setBrightness(float brightnessValue) {
+    @Override
+    public void setBrightness(float brightnessValue) {
         // Update the setting, which will eventually call back into DPC to have us actually update
         // the display with the new value.
         mBrightnessSetting.setBrightness(brightnessValue);
@@ -2511,6 +2548,7 @@
         }
     };
 
+    @Override
     public void dump(final PrintWriter pw) {
         synchronized (mLock) {
             pw.println();
@@ -2919,7 +2957,8 @@
         }
     }
 
-    void setAutoBrightnessLoggingEnabled(boolean enabled) {
+    @Override
+    public void setAutoBrightnessLoggingEnabled(boolean enabled) {
         if (mAutomaticBrightnessController != null) {
             mAutomaticBrightnessController.setLoggingEnabled(enabled);
         }
@@ -2930,14 +2969,16 @@
         sendUpdatePowerState();
     }
 
-    void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
+    @Override
+    public void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) {
         if (mDisplayWhiteBalanceController != null) {
             mDisplayWhiteBalanceController.setLoggingEnabled(enabled);
             mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled);
         }
     }
 
-    void setAmbientColorTemperatureOverride(float cct) {
+    @Override
+    public void setAmbientColorTemperatureOverride(float cct) {
         if (mDisplayWhiteBalanceController != null) {
             mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct);
             // The ambient color temperature override is only applied when the ambient color
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
new file mode 100644
index 0000000..6677f35
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.content.pm.ParceledListSlice;
+import android.hardware.display.AmbientBrightnessDayStats;
+import android.hardware.display.BrightnessChangeEvent;
+import android.hardware.display.BrightnessConfiguration;
+import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
+
+import java.io.PrintWriter;
+
+/**
+ * An interface to manage the display's power state and brightness
+ */
+public interface DisplayPowerControllerInterface {
+
+    /**
+     * Notified when the display is changed. We use this to apply any changes that might be needed
+     * when displays get swapped on foldable devices.
+     */
+    void onDisplayChanged();
+
+    /**
+     * Unregisters all listeners and interrupts all running threads; halting future work.
+     *
+     * This method should be called when the DisplayPowerController is no longer in use; i.e. when
+     * the display has been removed.
+     */
+    void stop();
+
+    /**
+     * Used to manage the displays preparing to transition from one device state to another.
+     */
+    void onDeviceStateTransition();
+
+    /**
+     * Used to update the display's BrightnessConfiguration
+     * @param config The new BrightnessConfiguration
+     */
+    void setBrightnessConfiguration(BrightnessConfiguration config);
+
+    /**
+     * Used to set the ambient color temperature of the Display
+     * @param ambientColorTemperature The target ambientColorTemperature
+     */
+    void setAmbientColorTemperatureOverride(float ambientColorTemperature);
+
+    /**
+     * Used to decide the associated AutomaticBrightnessController's BrightnessMode
+     * @param isIdle Flag which represents if the Idle BrightnessMode is to be set
+     */
+    void setAutomaticScreenBrightnessMode(boolean isIdle);
+
+    /**
+     * Used to enable/disable the logging of the WhileBalance associated entities
+     * @param enabled Flag which represents if the logging is the be enabled
+     */
+    void setDisplayWhiteBalanceLoggingEnabled(boolean enabled);
+
+    /**
+     * Used to dump the state.
+     * @param writer The PrintWriter used to dump the state.
+     */
+    void dump(PrintWriter writer);
+
+    /**
+     * Used to get the ambient brightness stats
+     */
+    ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(int userId);
+
+    /**
+     * Get the default brightness configuration
+     */
+    BrightnessConfiguration getDefaultBrightnessConfiguration();
+
+    /**
+     * Set the screen brightness of the associated display
+     * @param brightness The value to which the brightness is to be set
+     */
+    void setBrightness(float brightness);
+
+    /**
+     * Checks if the proximity sensor is available
+     */
+    boolean isProximitySensorAvailable();
+
+    /**
+     * Persist the brightness slider events and ambient brightness stats to disk.
+     */
+    void persistBrightnessTrackerState();
+
+    /**
+     * Ignores the proximity sensor until the sensor state changes, but only if the sensor is
+     * currently enabled and forcing the screen to be dark.
+     */
+    void ignoreProximitySensorUntilChanged();
+
+    /**
+     * Requests a new power state.
+     *
+     * @param request The requested power state.
+     * @param waitForNegativeProximity If true, issues a request to wait for
+     * negative proximity before turning the screen back on,
+     * assuming the screen was turned off by the proximity sensor.
+     * @return True if display is ready, false if there are important changes that must
+     * be made asynchronously.
+     */
+    boolean requestPowerState(DisplayManagerInternal.DisplayPowerRequest request,
+            boolean waitForNegativeProximity);
+
+    /**
+     * Sets up the temporary autobrightness adjustment when the user is yet to settle down to a
+     * value.
+     */
+    void setTemporaryAutoBrightnessAdjustment(float adjustment);
+
+    /**
+     * Gets the screen brightness setting
+     */
+    float getScreenBrightnessSetting();
+
+    /**
+     * Sets up the temporary brightness for the associated display
+     */
+    void setTemporaryBrightness(float brightness);
+
+    /**
+     * Gets the associated {@link BrightnessInfo}
+     */
+    BrightnessInfo getBrightnessInfo();
+
+    /**
+     * Get the {@link BrightnessChangeEvent}s for the specified user.
+     */
+    ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents(int userId, boolean hasUsageStats);
+
+    /**
+     * Sets up the logging for the associated {@link AutomaticBrightnessController}
+     * @param enabled Flag to represent if the logging is to be enabled
+     */
+    void setAutoBrightnessLoggingEnabled(boolean enabled);
+
+    /**
+     * Handles the changes to be done to update the brightness when the user is changed
+     * @param newUserId The new userId
+     */
+    void onSwitchUser(int newUserId);
+}
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
index 7a932ce..3413489 100644
--- a/services/core/java/com/android/server/display/HysteresisLevels.java
+++ b/services/core/java/com/android/server/display/HysteresisLevels.java
@@ -18,15 +18,12 @@
 
 import android.util.Slog;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.PrintWriter;
 import java.util.Arrays;
 
 /**
  * A helper class for handling access to illuminance hysteresis level values.
  */
-@VisibleForTesting
 public class HysteresisLevels {
     private static final String TAG = "HysteresisLevels";
 
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 38728ce..20b82c3 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -161,6 +161,13 @@
         }
     }
 
+    void setDisplayIdToMirror(IBinder appToken, int displayId) {
+        VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+        if (device != null) {
+            device.setDisplayIdToMirror(displayId);
+        }
+    }
+
     public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
         VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
         if (device != null) {
@@ -313,6 +320,15 @@
             return mDisplayIdToMirror;
         }
 
+        void setDisplayIdToMirror(int displayIdToMirror) {
+            if (mDisplayIdToMirror != displayIdToMirror) {
+                mDisplayIdToMirror = displayIdToMirror;
+                mInfo = null;
+                sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+                sendTraversalRequestLocked();
+            }
+        }
+
         @Override
         public boolean isWindowManagerMirroringLocked() {
             return mIsWindowManagerMirroring;
diff --git a/services/core/java/com/android/server/input/BatteryController.java b/services/core/java/com/android/server/input/BatteryController.java
new file mode 100644
index 0000000..c57d7e7
--- /dev/null
+++ b/services/core/java/com/android/server/input/BatteryController.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import android.annotation.BinderThread;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.input.IInputDeviceBatteryListener;
+import android.hardware.input.InputManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.view.InputDevice;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A thread-safe component of {@link InputManagerService} responsible for managing the battery state
+ * of input devices.
+ */
+final class BatteryController {
+    private static final String TAG = BatteryController.class.getSimpleName();
+
+    // To enable these logs, run:
+    // 'adb shell setprop log.tag.BatteryController DEBUG' (requires restart)
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final NativeInputManagerService mNative;
+
+    // Maps a pid to the registered listener record for that process. There can only be one battery
+    // listener per process.
+    @GuardedBy("mLock")
+    private final ArrayMap<Integer, ListenerRecord> mListenerRecords = new ArrayMap<>();
+
+    BatteryController(Context context, NativeInputManagerService nativeService) {
+        mContext = context;
+        mNative = nativeService;
+    }
+
+    /**
+     * Register the battery listener for the given input device and start monitoring its battery
+     * state.
+     */
+    @BinderThread
+    void registerBatteryListener(int deviceId, @NonNull IInputDeviceBatteryListener listener,
+            int pid) {
+        synchronized (mLock) {
+            ListenerRecord listenerRecord = mListenerRecords.get(pid);
+
+            if (listenerRecord == null) {
+                listenerRecord = new ListenerRecord(pid, listener);
+                try {
+                    listener.asBinder().linkToDeath(listenerRecord.mDeathRecipient, 0);
+                } catch (RemoteException e) {
+                    Slog.i(TAG, "Client died before battery listener could be registered.");
+                    return;
+                }
+                mListenerRecords.put(pid, listenerRecord);
+                if (DEBUG) Slog.d(TAG, "Battery listener added for pid " + pid);
+            }
+
+            if (listenerRecord.mListener.asBinder() != listener.asBinder()) {
+                throw new SecurityException(
+                        "Cannot register a new battery listener when there is already another "
+                                + "registered listener for pid "
+                                + pid);
+            }
+            if (!listenerRecord.mMonitoredDevices.add(deviceId)) {
+                throw new IllegalArgumentException(
+                        "The battery listener for pid " + pid
+                                + " is already monitoring deviceId " + deviceId);
+            }
+
+            if (DEBUG) {
+                Slog.d(TAG, "Battery listener for pid " + pid
+                        + " is monitoring deviceId " + deviceId);
+            }
+
+            notifyBatteryListener(deviceId, listenerRecord);
+        }
+    }
+
+    private void notifyBatteryListener(int deviceId, ListenerRecord record) {
+        final long eventTime = SystemClock.uptimeMillis();
+        try {
+            record.mListener.onBatteryStateChanged(
+                    deviceId,
+                    hasBattery(deviceId),
+                    mNative.getBatteryStatus(deviceId),
+                    mNative.getBatteryCapacity(deviceId) / 100.f,
+                    eventTime);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to notify listener", e);
+        }
+    }
+
+    private boolean hasBattery(int deviceId) {
+        final InputDevice device =
+                Objects.requireNonNull(mContext.getSystemService(InputManager.class))
+                        .getInputDevice(deviceId);
+        return device != null && device.hasBattery();
+    }
+
+    /**
+     * Unregister the battery listener for the given input device and stop monitoring its battery
+     * state. If there are no other input devices that this listener is monitoring, the listener is
+     * removed.
+     */
+    @BinderThread
+    void unregisterBatteryListener(int deviceId, @NonNull IInputDeviceBatteryListener listener,
+            int pid) {
+        synchronized (mLock) {
+            final ListenerRecord listenerRecord = mListenerRecords.get(pid);
+            if (listenerRecord == null) {
+                throw new IllegalArgumentException(
+                        "Cannot unregister battery callback: No listener registered for pid "
+                                + pid);
+            }
+
+            if (listenerRecord.mListener.asBinder() != listener.asBinder()) {
+                throw new IllegalArgumentException(
+                        "Cannot unregister battery callback: The listener is not the one that "
+                                + "is registered for pid "
+                                + pid);
+            }
+
+            if (!listenerRecord.mMonitoredDevices.contains(deviceId)) {
+                throw new IllegalArgumentException(
+                        "Cannot unregister battery callback: The device is not being "
+                                + "monitored for deviceId " + deviceId);
+            }
+
+            unregisterRecordLocked(listenerRecord, deviceId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void unregisterRecordLocked(ListenerRecord listenerRecord, int deviceId) {
+        final int pid = listenerRecord.mPid;
+
+        if (!listenerRecord.mMonitoredDevices.remove(deviceId)) {
+            throw new IllegalStateException("Cannot unregister battery callback: The deviceId "
+                    + deviceId
+                    + " is not being monitored by pid "
+                    + pid);
+        }
+
+        if (listenerRecord.mMonitoredDevices.isEmpty()) {
+            // There are no more devices being monitored by this listener.
+            listenerRecord.mListener.asBinder().unlinkToDeath(listenerRecord.mDeathRecipient, 0);
+            mListenerRecords.remove(pid);
+            if (DEBUG) Slog.d(TAG, "Battery listener removed for pid " + pid);
+        }
+    }
+
+    private void handleListeningProcessDied(int pid) {
+        synchronized (mLock) {
+            final ListenerRecord listenerRecord = mListenerRecords.get(pid);
+            if (listenerRecord == null) {
+                return;
+            }
+            if (DEBUG) {
+                Slog.d(TAG,
+                        "Removing battery listener for pid " + pid + " because the process died");
+            }
+            for (final int deviceId : listenerRecord.mMonitoredDevices) {
+                unregisterRecordLocked(listenerRecord, deviceId);
+            }
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        synchronized (mLock) {
+            pw.println(prefix + TAG + ": " + mListenerRecords.size()
+                    + " battery listeners");
+            for (int i = 0; i < mListenerRecords.size(); i++) {
+                pw.println(prefix + "  " + i + ": " + mListenerRecords.valueAt(i));
+            }
+        }
+    }
+
+    @SuppressWarnings("all")
+    void monitor() {
+        synchronized (mLock) {
+            return;
+        }
+    }
+
+    // A record of a registered battery listener from one process.
+    private class ListenerRecord {
+        final int mPid;
+        final IInputDeviceBatteryListener mListener;
+        final IBinder.DeathRecipient mDeathRecipient;
+        // The set of deviceIds that are currently being monitored by this listener.
+        final Set<Integer> mMonitoredDevices;
+
+        ListenerRecord(int pid, IInputDeviceBatteryListener listener) {
+            mPid = pid;
+            mListener = listener;
+            mMonitoredDevices = new ArraySet<>();
+            mDeathRecipient = () -> handleListeningProcessDied(pid);
+        }
+
+        @Override
+        public String toString() {
+            return "pid=" + mPid
+                    + ", monitored devices=" + Arrays.toString(mMonitoredDevices.toArray());
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index fe9e68d..3def714 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -48,6 +48,7 @@
 import android.hardware.SensorPrivacyManagerInternal;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayViewport;
+import android.hardware.input.IInputDeviceBatteryListener;
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
 import android.hardware.input.IInputSensorEventListener;
@@ -308,6 +309,9 @@
     @GuardedBy("mInputMonitors")
     final Map<IBinder, GestureMonitorSpyWindow> mInputMonitors = new HashMap<>();
 
+    // Manages battery state for input devices.
+    private final BatteryController mBatteryController;
+
     // Maximum number of milliseconds to wait for input event injection.
     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
 
@@ -417,6 +421,7 @@
         mContext = injector.getContext();
         mHandler = new InputManagerHandler(injector.getLooper());
         mNative = injector.getNativeService(this);
+        mBatteryController = new BatteryController(mContext, mNative);
 
         mUseDevInputEventForAudioJack =
                 mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
@@ -2653,6 +2658,18 @@
     }
 
     @Override
+    public void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener) {
+        Objects.requireNonNull(listener);
+        mBatteryController.registerBatteryListener(deviceId, listener, Binder.getCallingPid());
+    }
+
+    @Override
+    public void unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener) {
+        Objects.requireNonNull(listener);
+        mBatteryController.unregisterBatteryListener(deviceId, listener, Binder.getCallingPid());
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
@@ -2665,7 +2682,8 @@
         pw.println("Input Manager Service (Java) State:");
         dumpAssociations(pw, "  " /*prefix*/);
         dumpSpyWindowGestureMonitors(pw, "  " /*prefix*/);
-        dumpDisplayInputPropertiesValues(pw, "  " /* prefix */);
+        dumpDisplayInputPropertiesValues(pw, "  " /*prefix*/);
+        mBatteryController.dump(pw, "  " /*prefix*/);
     }
 
     private void dumpAssociations(PrintWriter pw, String prefix) {
@@ -2776,6 +2794,7 @@
         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
         synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
         synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
+        mBatteryController.monitor();
         mNative.monitor();
     }
 
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 325c308..63c0a88 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.input;
 
+import android.annotation.Nullable;
 import android.hardware.display.DisplayViewport;
 import android.hardware.input.InputSensorInfo;
 import android.hardware.lights.Light;
@@ -28,16 +29,13 @@
 import android.view.PointerIcon;
 import android.view.VerifiedInputEvent;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.util.List;
 
 /**
  * An interface for the native methods of InputManagerService. We use a public interface so that
  * this can be mocked for testing by Mockito.
  */
-@VisibleForTesting
-public interface NativeInputManagerService {
+interface NativeInputManagerService {
 
     void start();
 
@@ -141,6 +139,13 @@
 
     int getBatteryStatus(int deviceId);
 
+    /**
+     * Get the device path of the battery for an input device.
+     * @return the path for the input device battery, or null if there is none.
+     */
+    @Nullable
+    String getBatteryDevicePath(int deviceId);
+
     List<Light> getLights(int deviceId);
 
     int getLightPlayerId(int deviceId, int lightId);
@@ -327,6 +332,9 @@
         public native int getBatteryStatus(int deviceId);
 
         @Override
+        public native String getBatteryDevicePath(int deviceId);
+
+        @Override
         public native List<Light> getLights(int deviceId);
 
         @Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodDeviceConfigs.java b/services/core/java/com/android/server/inputmethod/InputMethodDeviceConfigs.java
new file mode 100644
index 0000000..9d5393f
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/InputMethodDeviceConfigs.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import static android.provider.InputMethodManagerDeviceConfig.KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS;
+
+import android.app.ActivityThread;
+import android.provider.DeviceConfig;
+
+/**
+ * Class for the device-level configuration related to the input method manager
+ * platform features in {@link DeviceConfig}.
+ */
+public final class InputMethodDeviceConfigs {
+    private boolean mHideImeWhenNoEditorFocus;
+    private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
+
+    public InputMethodDeviceConfigs() {
+        mDeviceConfigChangedListener = properties -> {
+            if (!DeviceConfig.NAMESPACE_INPUT_METHOD_MANAGER.equals(properties.getNamespace())) {
+                return;
+            }
+            for (String name : properties.getKeyset()) {
+                if (KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS.equals(name)) {
+                    mHideImeWhenNoEditorFocus = properties.getBoolean(name,
+                            true /* defaultValue */);
+                }
+            }
+        };
+        mHideImeWhenNoEditorFocus = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_INPUT_METHOD_MANAGER,
+                KEY_HIDE_IME_WHEN_NO_EDITOR_FOCUS, true);
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_INPUT_METHOD_MANAGER,
+                ActivityThread.currentApplication().getMainExecutor(),
+                mDeviceConfigChangedListener);
+    }
+
+    /**
+     * Whether the IME should be hidden when the window gained focus without an editor focused.
+     */
+    public boolean shouldHideImeWhenNoEditorFocus() {
+        return mHideImeWhenNoEditorFocus;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7bd835c..729de41 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -303,6 +303,7 @@
     final PackageManagerInternal mPackageManagerInternal;
     final InputManagerInternal mInputManagerInternal;
     final ImePlatformCompatUtils mImePlatformCompatUtils;
+    final InputMethodDeviceConfigs mInputMethodDeviceConfigs;
     private final DisplayManagerInternal mDisplayManagerInternal;
     final boolean mHasFeature;
     private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
@@ -1732,6 +1733,7 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mImePlatformCompatUtils = new ImePlatformCompatUtils();
+        mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
         mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
@@ -3889,6 +3891,18 @@
                                 SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
                     }
                 }
+                if (!isTextEditor && mInputShown && startInputByWinGainedFocus
+                        && mInputMethodDeviceConfigs.shouldHideImeWhenNoEditorFocus()) {
+                    // Hide the soft-keyboard when the system do nothing for softInputModeState
+                    // of the window being gained focus without an editor. This behavior benefits
+                    // to resolve some unexpected IME visible cases while that window with following
+                    // configurations being switched from an IME shown window:
+                    // 1) SOFT_INPUT_STATE_UNCHANGED state without an editor
+                    // 2) SOFT_INPUT_STATE_VISIBLE state without an editor
+                    // 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
+                    hideCurrentInputLocked(mCurFocusedWindow, 0, null,
+                            SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR);
+                }
                 res = startInputUncheckedLocked(cs, inputContext,
                         remoteAccessibilityInputConnection, editorInfo, startInputFlags,
                         startInputReason, unverifiedTargetSdkVersion,
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java b/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
index 071917c..058c1c8 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
@@ -19,6 +19,8 @@
 import android.hardware.location.NanoAppMessage;
 import android.util.Log;
 
+import java.util.Collection;
+
 /**
  * A class to log events and useful metrics within the Context Hub service.
  *
@@ -217,6 +219,18 @@
     }
 
     /**
+     * Clears all queues of events.
+     */
+    public synchronized void clear() {
+        for (Collection<?> deque:
+                new Collection<?>[] {mNanoappLoadEventQueue, mNanoappUnloadEventQueue,
+                                     mMessageFromNanoappQueue, mMessageToNanoappQueue,
+                                     mContextHubRestartEventQueue}) {
+            deque.clear();
+        }
+    }
+
+    /**
      * Logs a nanoapp load event
      *
      * @param contextHubId      the ID of the context hub
@@ -311,12 +325,8 @@
         }
     }
 
-    /**
-     * Creates a string representation of the logged events
-     *
-     * @return the dumped events
-     */
-    public synchronized String dump() {
+    @Override
+    public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("Nanoapp Loads:");
         sb.append(System.lineSeparator());
@@ -354,9 +364,4 @@
         }
         return sb.toString();
     }
-
-    @Override
-    public String toString() {
-        return dump();
-    }
 }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 4ca0ea6..7ce1017 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1054,7 +1054,7 @@
 
         pw.println("");
         pw.println("=================== EVENTS ====================");
-        pw.println(ContextHubEventLogger.getInstance().dump());
+        pw.println(ContextHubEventLogger.getInstance());
 
         // dump eventLog
     }
diff --git a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
index 98bae3d..811e96c 100644
--- a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
+++ b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
@@ -96,6 +96,7 @@
 
         // show Alert
         mAlert = mAlertDialog.create();
+        mAlert.getWindow().setHideOverlayWindows(true);
         mAlert.show();
 
         // set Alert Timeout
diff --git a/services/core/java/com/android/server/logcat/OWNERS b/services/core/java/com/android/server/logcat/OWNERS
index 87d30f3..4ce93aa 100644
--- a/services/core/java/com/android/server/logcat/OWNERS
+++ b/services/core/java/com/android/server/logcat/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1218649
+
 cbrubaker@google.com
 eunjeongshin@google.com
 georgechan@google.com
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index d91bf8c..9466a6f5 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -287,7 +287,7 @@
                 name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
             } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
                 type = TYPE_HDMI;
-                name = com.android.internal.R.string.default_audio_route_name_hdmi;
+                name = com.android.internal.R.string.default_audio_route_name_external_device;
             } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
                 type = TYPE_USB_DEVICE;
                 name = com.android.internal.R.string.default_audio_route_name_usb;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0b4f736..5d64176 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1978,34 +1978,39 @@
             return (haystack & needle) != 0;
         }
 
-        public boolean isInLockDownMode() {
-            return mIsInLockDownMode;
+        // Return whether the user is in lockdown mode.
+        // If the flag is not set, we assume the user is not in lockdown.
+        public boolean isInLockDownMode(int userId) {
+            return mUserInLockDownMode.get(userId, false);
         }
 
         @Override
         public synchronized void onStrongAuthRequiredChanged(int userId) {
             boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
                     STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
-            mUserInLockDownMode.put(userId, userInLockDownModeNext);
-            boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1;
 
-            if (mIsInLockDownMode == isInLockDownModeNext) {
+            // Nothing happens if the lockdown mode of userId keeps the same.
+            if (userInLockDownModeNext == isInLockDownMode(userId)) {
                 return;
             }
 
-            if (isInLockDownModeNext) {
-                cancelNotificationsWhenEnterLockDownMode();
+            // When the lockdown mode is changed, we perform the following steps.
+            // If the userInLockDownModeNext is true, all the function calls to
+            // notifyPostedLocked and notifyRemovedLocked will not be executed.
+            // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked
+            // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked.
+            // So we shall call cancelNotificationsWhenEnterLockDownMode before
+            // we set mUserInLockDownMode as true.
+            // On the other hand, if the userInLockDownModeNext is false, we shall call
+            // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode
+            if (userInLockDownModeNext) {
+                cancelNotificationsWhenEnterLockDownMode(userId);
             }
 
-            // When the mIsInLockDownMode is true, both notifyPostedLocked and
-            // notifyRemovedLocked will be dismissed. So we shall call
-            // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode
-            // as true and call postNotificationsWhenExitLockDownMode after we set
-            // mIsInLockDownMode as false.
-            mIsInLockDownMode = isInLockDownModeNext;
+            mUserInLockDownMode.put(userId, userInLockDownModeNext);
 
-            if (!isInLockDownModeNext) {
-                postNotificationsWhenExitLockDownMode();
+            if (!userInLockDownModeNext) {
+                postNotificationsWhenExitLockDownMode(userId);
             }
         }
     }
@@ -9712,11 +9717,14 @@
         }
     }
 
-    private void cancelNotificationsWhenEnterLockDownMode() {
+    private void cancelNotificationsWhenEnterLockDownMode(int userId) {
         synchronized (mNotificationLock) {
             int numNotifications = mNotificationList.size();
             for (int i = 0; i < numNotifications; i++) {
                 NotificationRecord rec = mNotificationList.get(i);
+                if (rec.getUser().getIdentifier() != userId) {
+                    continue;
+                }
                 mListeners.notifyRemovedLocked(rec, REASON_LOCKDOWN,
                         rec.getStats());
             }
@@ -9724,14 +9732,23 @@
         }
     }
 
-    private void postNotificationsWhenExitLockDownMode() {
+    private void postNotificationsWhenExitLockDownMode(int userId) {
         synchronized (mNotificationLock) {
             int numNotifications = mNotificationList.size();
+            // Set the delay to spread out the burst of notifications.
+            long delay = 0;
             for (int i = 0; i < numNotifications; i++) {
                 NotificationRecord rec = mNotificationList.get(i);
-                mListeners.notifyPostedLocked(rec, rec);
+                if (rec.getUser().getIdentifier() != userId) {
+                    continue;
+                }
+                mHandler.postDelayed(() -> {
+                    synchronized (mNotificationLock) {
+                        mListeners.notifyPostedLocked(rec, rec);
+                    }
+                }, delay);
+                delay += 20;
             }
-
         }
     }
 
@@ -9910,6 +9927,9 @@
 
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
+            if (isInLockDownMode(record.getUser().getIdentifier())) {
+                continue;
+            }
             if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) {
                 continue;
             }
@@ -9951,8 +9971,8 @@
                 rankings.toArray(new NotificationListenerService.Ranking[0]));
     }
 
-    boolean isInLockDownMode() {
-        return mStrongAuthTracker.isInLockDownMode();
+    boolean isInLockDownMode(int userId) {
+        return mStrongAuthTracker.isInLockDownMode(userId);
     }
 
     boolean hasCompanionDevice(ManagedServiceInfo info) {
@@ -11014,7 +11034,7 @@
         @GuardedBy("mNotificationLock")
         void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
                 boolean notifyAllListeners) {
-            if (isInLockDownMode()) {
+            if (isInLockDownMode(r.getUser().getIdentifier())) {
                 return;
             }
 
@@ -11120,7 +11140,7 @@
         @GuardedBy("mNotificationLock")
         public void notifyRemovedLocked(NotificationRecord r, int reason,
                 NotificationStats notificationStats) {
-            if (isInLockDownMode()) {
+            if (isInLockDownMode(r.getUser().getIdentifier())) {
                 return;
             }
 
@@ -11169,10 +11189,6 @@
          */
         @GuardedBy("mNotificationLock")
         public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
-            if (isInLockDownMode()) {
-                return;
-            }
-
             boolean isHiddenRankingUpdate = changedHiddenNotifications != null
                     && changedHiddenNotifications.size() > 0;
             // TODO (b/73052211): if the ranking update changed the notification type,
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 477b8da..d8aa469 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -106,7 +106,7 @@
     private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
 
     @VisibleForTesting
-    static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 50000;
+    static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
     @VisibleForTesting
     static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 50000;
 
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index f3cb7fb..b611b5d 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -31,7 +31,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index c4b6485..c35d8631 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.IOException;
 import java.util.List;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 7159673..1c78528 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -84,7 +84,7 @@
 import com.android.server.SystemService;
 import com.android.server.pm.KnownPackages;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import libcore.util.EmptyArray;
 
@@ -1098,6 +1098,7 @@
         private void enforceActor(@NonNull OverlayIdentifier overlay, @NonNull String methodName,
                 int realUserId) throws SecurityException {
             OverlayInfo overlayInfo = mImpl.getOverlayInfo(overlay, realUserId);
+
             if (overlayInfo == null) {
                 throw new IllegalArgumentException("Unable to retrieve overlay information for "
                         + overlay);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index dade7aa..8e672c3 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -47,7 +47,7 @@
 
 import com.android.internal.content.om.OverlayConfig;
 import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -519,6 +519,7 @@
             throws OperationFailedException {
         final OverlayIdentifier overlayIdentifier = new OverlayIdentifier(
                 info.packageName, info.overlayName);
+
         final Set<PackageAndUser> updatedTargets = new ArraySet<>();
         OverlayInfo oi = mSettings.getNullableOverlayInfo(overlayIdentifier, userId);
         if (oi != null) {
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index 539fecf..fdceabe 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -28,7 +28,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java
index 750f5c3..cbdabdd 100644
--- a/services/core/java/com/android/server/om/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/om/PackageManagerHelper.java
@@ -19,19 +19,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.om.OverlayableInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.os.RemoteException;
 import android.util.ArrayMap;
-import android.util.Slog;
 
 import com.android.server.pm.PackageManagerServiceUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 01ddc48..71593e1 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -49,7 +49,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.modules.utils.build.UnboundedSdkLevel;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedApexSystemService;
 import com.android.server.utils.TimingsTraceAndSlog;
 
diff --git a/services/core/java/com/android/server/pm/ApexPackageInfo.java b/services/core/java/com/android/server/pm/ApexPackageInfo.java
index 73cb0ad..4dd9c49 100644
--- a/services/core/java/com/android/server/pm/ApexPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ApexPackageInfo.java
@@ -31,9 +31,9 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index c2f2b0a..a286160 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -64,7 +64,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.security.VerityUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index da8992a..0f5d8fd 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -45,8 +45,8 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.pm.dex.ArtManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SELinuxUtil;
 
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 5b3eff9..14140b5 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -40,7 +40,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.function.QuadFunction;
 import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index 5e0b47a..79d72a3 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -51,8 +51,8 @@
 import com.android.server.FgThread;
 import com.android.server.compat.CompatChange;
 import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
 import com.android.server.pm.pkg.component.ParsedPermission;
diff --git a/services/core/java/com/android/server/pm/AppsFilterSnapshot.java b/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
index de037f3..dd84e06 100644
--- a/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
+++ b/services/core/java/com/android/server/pm/AppsFilterSnapshot.java
@@ -23,7 +23,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.function.QuadFunction;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 
diff --git a/services/core/java/com/android/server/pm/AppsFilterUtils.java b/services/core/java/com/android/server/pm/AppsFilterUtils.java
index 3a105c0..7daa0b9 100644
--- a/services/core/java/com/android/server/pm/AppsFilterUtils.java
+++ b/services/core/java/com/android/server/pm/AppsFilterUtils.java
@@ -23,7 +23,7 @@
 import android.content.IntentFilter;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedComponent;
 import com.android.server.pm.pkg.component.ParsedIntentInfo;
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index ab99860..5916196 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -48,7 +48,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index d442fb2..3211ca1 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -129,9 +129,9 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index bda7b82..9f6aa63 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -60,8 +60,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -572,7 +572,7 @@
         if (deleteCodeAndResources && (outInfo != null)) {
             outInfo.mArgs = new InstallArgs(
                     ps.getPathString(), getAppDexInstructionSets(
-                            ps.getPrimaryCpuAbi(), ps.getSecondaryCpuAbi()), mPm);
+                            ps.getPrimaryCpuAbi(), ps.getSecondaryCpuAbi()));
             if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.mArgs);
         }
     }
@@ -673,6 +673,18 @@
         final String packageName = versionedPackage.getPackageName();
         final long versionCode = versionedPackage.getLongVersionCode();
 
+        if (mPm.mProtectedPackages.isPackageDataProtected(userId, packageName)) {
+            mPm.mHandler.post(() -> {
+                try {
+                    Slog.w(TAG, "Attempted to delete protected package: " + packageName);
+                    observer.onPackageDeleted(packageName,
+                            PackageManager.DELETE_FAILED_INTERNAL_ERROR, null);
+                } catch (RemoteException re) {
+                }
+            });
+            return;
+        }
+
         try {
             if (mPm.mInjector.getLocalService(ActivityTaskManagerInternal.class)
                     .isBaseOfLockedTask(packageName)) {
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index d501386..2b8a196 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -58,8 +58,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.DexFile;
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index 4134671..624d005 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -26,7 +26,7 @@
 import android.os.UserHandle;
 
 import com.android.server.DeviceIdleInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
diff --git a/services/core/java/com/android/server/pm/FeatureConfig.java b/services/core/java/com/android/server/pm/FeatureConfig.java
index 6e356de..1a57743 100644
--- a/services/core/java/com/android/server/pm/FeatureConfig.java
+++ b/services/core/java/com/android/server/pm/FeatureConfig.java
@@ -19,7 +19,7 @@
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 @VisibleForTesting(visibility = PRIVATE)
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 52e3fd9..797d4c3 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -52,7 +52,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.pm.parsing.PackageCacher;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.utils.WatchedArrayMap;
 
@@ -227,7 +227,7 @@
             }
         }
         final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
-                consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
+                consumer -> mPm.forEachPackageInternal(mPm.snapshotComputer(),
                         pkg -> consumer.accept(pkg, pkg.isSystem(),
                                 apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
 
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
index 616bb8f..65c2378 100644
--- a/services/core/java/com/android/server/pm/InstallArgs.java
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -65,9 +65,6 @@
     // if we move dex files under the common app path.
     @Nullable String[] mInstructionSets;
 
-    @NonNull final PackageManagerService mPm;
-    @NonNull final RemovePackageHelper mRemovePackageHelper;
-
     InstallArgs(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
             int installFlags, InstallSource installSource, String volumeUuid,
             UserHandle user, String[] instructionSets,
@@ -76,7 +73,7 @@
             int autoRevokePermissionsMode,
             String traceMethod, int traceCookie, SigningDetails signingDetails,
             int installReason, int installScenario, boolean forceQueryableOverride,
-            int dataLoaderType, int packageSource, PackageManagerService pm) {
+            int dataLoaderType, int packageSource) {
         mOriginInfo = originInfo;
         mMoveInfo = moveInfo;
         mInstallFlags = installFlags;
@@ -97,8 +94,6 @@
         mForceQueryableOverride = forceQueryableOverride;
         mDataLoaderType = dataLoaderType;
         mPackageSource = packageSource;
-        mPm = pm;
-        mRemovePackageHelper = new RemovePackageHelper(mPm);
     }
 
     /** New install */
@@ -110,19 +105,19 @@
                 params.mAutoRevokePermissionsMode,
                 params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
                 params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
-                params.mDataLoaderType, params.mPackageSource, params.mPm);
+                params.mDataLoaderType, params.mPackageSource);
     }
 
     /**
      * Create args that describe an existing installed package. Typically used
      * when cleaning up old installs, or used as a move source.
      */
-    InstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) {
+    InstallArgs(String codePath, String[] instructionSets) {
         this(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
                 null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
                 SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN,
                 PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE,
-                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, pm);
+                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
         mCodeFile = (codePath != null) ? new File(codePath) : null;
     }
 
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 9db9837..d201710 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -23,7 +23,6 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
@@ -163,11 +162,11 @@
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageCacher;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.Permission;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
@@ -1420,9 +1419,7 @@
         }
 
         if (!isApex) {
-            if (!doRenameLI(args, res.mReturnCode, parsedPackage)) {
-                throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
-            }
+            doRenameLI(args, res.mReturnCode, res.mReturnMsg, parsedPackage);
 
             try {
                 setUpFsVerityIfPossible(parsedPackage);
@@ -1689,19 +1686,20 @@
      * scanned package should be updated to reflect the rename.
      */
     @GuardedBy("mPm.mInstallLock")
-    private boolean doRenameLI(InstallArgs args, int status, ParsedPackage parsedPackage) {
+    private void doRenameLI(InstallArgs args, int status, String statusMsg,
+            ParsedPackage parsedPackage) throws PrepareFailure {
         if (args.mMoveInfo != null) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 mRemovePackageHelper.cleanUpForMoveInstall(args.mMoveInfo.mToUuid,
                         args.mMoveInfo.mPackageName, args.mMoveInfo.mFromCodePath);
-                return false;
+                throw new PrepareFailure(status, statusMsg);
             }
-            return true;
+            return;
         }
         // For file installations
         if (status != PackageManager.INSTALL_SUCCEEDED) {
             mRemovePackageHelper.removeCodePath(args.mCodeFile);
-            return false;
+            throw new PrepareFailure(status, statusMsg);
         }
 
         final File targetDir = resolveTargetDir(args);
@@ -1723,12 +1721,14 @@
             }
         } catch (IOException | ErrnoException e) {
             Slog.w(TAG, "Failed to rename", e);
-            return false;
+            throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE,
+                    "Failed to rename");
         }
 
         if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
             Slog.w(TAG, "Failed to restorecon");
-            return false;
+            throw new PrepareFailure(PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE,
+                    "Failed to restorecon");
         }
 
         // Reflect the rename internally
@@ -1739,14 +1739,13 @@
             parsedPackage.setPath(afterCodeFile.getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
-            return false;
+            throw new PrepareFailure(PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE,
+                    "Failed to get path: " + afterCodeFile);
         }
         parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
                 afterCodeFile, parsedPackage.getBaseApkPath()));
         parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
                 afterCodeFile, parsedPackage.getSplitCodePaths()));
-
-        return true;
     }
 
     // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
@@ -1938,7 +1937,7 @@
                                         AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
                                                 deletedPkgSetting),
                                         AndroidPackageUtils.getSecondaryCpuAbi(oldPackage,
-                                                deletedPkgSetting)), mPm);
+                                                deletedPkgSetting)));
                     } else {
                         res.mRemovedInfo.mArgs = null;
                     }
@@ -3312,7 +3311,8 @@
             if (disabledPs == null) {
                 logCriticalInfo(Log.WARN, "System package " + packageName
                         + " no longer exists; its data will be wiped");
-                mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false);
+                mInjector.getHandler().post(
+                        () -> mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false));
             } else {
                 // we still have a disabled system package, but, it still might have
                 // been removed. check the code path still exists and check there's
@@ -3938,7 +3938,7 @@
 
             final InstallArgs args = new InstallArgs(
                     pkgSetting.getPathString(), getAppDexInstructionSets(
-                    pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()), mPm);
+                    pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()));
             mRemovePackageHelper.cleanUpResources(args);
             synchronized (mPm.mLock) {
                 mPm.mSettings.enableSystemPackageLPw(pkgSetting.getPackageName());
@@ -4023,8 +4023,7 @@
                                 + parsedPackage.getPath());
                 InstallArgs args = new InstallArgs(
                         pkgSetting.getPathString(), getAppDexInstructionSets(
-                        pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()),
-                        mPm);
+                        pkgSetting.getPrimaryCpuAbi(), pkgSetting.getSecondaryCpuAbi()));
                 mRemovePackageHelper.cleanUpResources(args);
             } else {
                 // The application on /system is older than the application on /data. Hide
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 0630ccd..a7f1727 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -51,7 +51,7 @@
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.Preconditions;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import libcore.io.IoUtils;
 
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 39a2839..71bd2d7 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -56,9 +56,9 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index 2d42107..f1cfc5b 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -21,9 +21,6 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-
 import dalvik.system.VMRuntime;
 
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 5c29833..7774b6a 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -30,7 +30,7 @@
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.utils.WatchedArrayMap;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 59bd427..c38b822 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -96,7 +96,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index df02223..b27373e 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -55,8 +55,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index e4dcf1a..5507b44 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -38,8 +38,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexoptOptions;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index 1dbab90..9bea599 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -22,9 +22,9 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 73d81ba..75f5f93 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -40,8 +40,8 @@
 
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4b6543b..3fb4066 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -77,8 +77,8 @@
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.DexoptUtils;
 import com.android.server.pm.dex.PackageDexUsage;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.DexFile;
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
index 1c25dbb..247abf3 100644
--- a/services/core/java/com/android/server/pm/PackageInstalledInfo.java
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -22,7 +22,7 @@
 import android.util.ExceptionUtils;
 import android.util.Slog;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index df02fe1..e9f26e9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -152,7 +152,7 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 330e3313..65e7ce1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -49,9 +49,8 @@
 
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DynamicCodeLogger;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.SharedUserApi;
@@ -155,7 +154,7 @@
     @Nullable
     @Override
     @Deprecated
-    public final AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
+    public final AndroidPackage getAndroidPackage(@NonNull String packageName) {
         return snapshot().getPackage(packageName);
     }
 
@@ -466,6 +465,20 @@
                 filterCallingUid);
     }
 
+    /**
+     * @deprecated similar to {@link resolveIntent} but limits the matches to exported components.
+     */
+    @Override
+    @Deprecated
+    public final ResolveInfo resolveIntentExported(Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
+            boolean resolveForStart, int filterCallingUid) {
+        return getResolveIntentHelper().resolveIntentInternal(snapshot(),
+                intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
+                filterCallingUid, true);
+    }
+
     @Override
     @Deprecated
     public final ResolveInfo resolveService(Intent intent, String resolvedType,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 752ebf3..259202f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -203,13 +203,14 @@
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 import com.android.server.pm.permission.LegacyPermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -6716,6 +6717,19 @@
         }
     }
 
+    void forEachPackageInternal(@NonNull Computer snapshot,
+            @NonNull Consumer<AndroidPackageInternal> consumer) {
+        final ArrayMap<String, ? extends PackageStateInternal> packageStates =
+                snapshot.getPackageStates();
+        int size = packageStates.size();
+        for (int index = 0; index < size; index++) {
+            PackageStateInternal packageState = packageStates.valueAt(index);
+            if (packageState.getPkg() != null) {
+                consumer.accept(packageState.getPkg());
+            }
+        }
+    }
+
     private void forEachPackageState(
             @NonNull ArrayMap<String, ? extends PackageStateInternal> packageStates,
             @NonNull Consumer<PackageStateInternal> consumer) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index ec1b29e..4391fdd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -34,8 +34,8 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index f466655..77334e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -93,7 +93,7 @@
 import com.android.server.Watchdog;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.dex.PackageDexUsage;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
 import com.android.server.pm.resolution.ComponentResolverApi;
diff --git a/services/core/java/com/android/server/pm/PackageProperty.java b/services/core/java/com/android/server/pm/PackageProperty.java
index 2055537..241f143 100644
--- a/services/core/java/com/android/server/pm/PackageProperty.java
+++ b/services/core/java/com/android/server/pm/PackageProperty.java
@@ -27,12 +27,12 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
 import android.content.pm.PackageManager.PropertyLocation;
-import com.android.server.pm.pkg.component.ParsedComponent;
 import android.os.Binder;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedComponent;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index f84db1f..4764a5c 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -41,10 +41,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.LegacyPermissionState;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUnserialized;
@@ -126,7 +127,7 @@
      * @see PackageState#getAndroidPackage()
      */
     @Nullable
-    private AndroidPackage pkg;
+    private AndroidPackageInternal pkg;
 
     /** @see AndroidPackage#getPath() */
     @NonNull
@@ -418,8 +419,9 @@
         return hasChanges;
     }
 
+    // TODO: Remove, only commit package when it's actually finalized
     public PackageSetting setPkg(AndroidPackage pkg) {
-        this.pkg = pkg;
+        this.pkg = (AndroidPackageInternal) pkg;
         onChanged();
         return this;
     }
@@ -1165,7 +1167,7 @@
 
     @Nullable
     @Override
-    public AndroidPackageApi getAndroidPackage() {
+    public AndroidPackage getAndroidPackage() {
         return getPkg();
     }
 
@@ -1366,7 +1368,7 @@
      * @see PackageState#getAndroidPackage()
      */
     @DataClass.Generated.Member
-    public @Nullable AndroidPackage getPkg() {
+    public @Nullable AndroidPackageInternal getPkg() {
         return pkg;
     }
 
@@ -1473,10 +1475,10 @@
     }
 
     @DataClass.Generated(
-            time = 1644270960923L,
+            time = 1659546705292L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
-            inputSignatures = "private  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n  android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+            inputSignatures = "private  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackageInternal)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/PrepareResult.java b/services/core/java/com/android/server/pm/PrepareResult.java
index 4e08e16..e074f44a 100644
--- a/services/core/java/com/android/server/pm/PrepareResult.java
+++ b/services/core/java/com/android/server/pm/PrepareResult.java
@@ -18,8 +18,8 @@
 
 import android.annotation.Nullable;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * The set of data needed to successfully install the prepared package. This includes data that
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index d6a133e..0f7c652 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -30,8 +30,8 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.utils.WatchedLongSparseArray;
 
diff --git a/services/core/java/com/android/server/pm/ReconcileRequest.java b/services/core/java/com/android/server/pm/ReconcileRequest.java
index 9e4e986..84b292f 100644
--- a/services/core/java/com/android/server/pm/ReconcileRequest.java
+++ b/services/core/java/com/android/server/pm/ReconcileRequest.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Collections;
 import java.util.Map;
diff --git a/services/core/java/com/android/server/pm/ReconciledPackage.java b/services/core/java/com/android/server/pm/ReconciledPackage.java
index 1bfe357..3bb5a1b 100644
--- a/services/core/java/com/android/server/pm/ReconciledPackage.java
+++ b/services/core/java/com/android/server/pm/ReconciledPackage.java
@@ -22,7 +22,7 @@
 import android.content.pm.SigningDetails;
 import android.util.ArrayMap;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index f083b67..a025965 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -46,9 +46,9 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.parsing.PackageCacher;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
 
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 24ed621..fada577 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -52,8 +52,9 @@
 
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.am.ActivityManagerService;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.resolution.ComponentResolverApi;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
@@ -100,6 +101,38 @@
         mInstantAppInstallerActivitySupplier = instantAppInstallerActivitySupplier;
     }
 
+    private static void filterNonExportedComponents(Intent intent, int filterCallingUid,
+            List<ResolveInfo> query, PlatformCompat platformCompat, Computer computer) {
+        if (query == null
+                || intent.getPackage() != null
+                || intent.getComponent() != null
+                || ActivityManager.canAccessUnexportedComponents(filterCallingUid)) {
+            return;
+        }
+        AndroidPackage caller = computer.getPackage(filterCallingUid);
+        String callerPackage = caller == null ? "Not specified" : caller.getPackageName();
+        for (int i = query.size() - 1; i >= 0; i--) {
+            if (!query.get(i).getComponentInfo().exported) {
+                if (!platformCompat.isChangeEnabledByUid(
+                        ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS,
+                        filterCallingUid)) {
+                    Slog.w(TAG, "Non-exported component not filtered out "
+                            + "(will be filtered out once the app targets U+)- intent: "
+                            + intent.getAction() + ", component: "
+                            + query.get(i).getComponentInfo()
+                            .getComponentName().flattenToShortString()
+                            + ", starter: " + callerPackage);
+                    return;
+                }
+                Slog.w(TAG, "Non-exported component filtered out - intent: "
+                        + intent.getAction() + ", component: "
+                        + query.get(i).getComponentInfo().getComponentName().flattenToShortString()
+                        + ", starter: " + callerPackage);
+                query.remove(i);
+            }
+        }
+    }
+
     /**
      * Normally instant apps can only be resolved when they're visible to the caller.
      * However, if {@code resolveForStart} is {@code true}, all instant apps are visible
@@ -109,6 +142,20 @@
             @PackageManager.ResolveInfoFlagsBits long flags,
             @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
             boolean resolveForStart, int filterCallingUid) {
+        return resolveIntentInternal(computer, intent, resolvedType, flags,
+                privateResolveFlags, userId, resolveForStart, filterCallingUid, false);
+    }
+
+    /**
+     * Normally instant apps can only be resolved when they're visible to the caller.
+     * However, if {@code resolveForStart} is {@code true}, all instant apps are visible
+     * since we need to allow the system to start any installed application.
+     * Allows picking exported components only.
+     */
+    public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType,
+            @PackageManager.ResolveInfoFlagsBits long flags,
+            @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
+            boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
 
@@ -124,6 +171,10 @@
             final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent,
                     resolvedType, flags, privateResolveFlags, filterCallingUid, userId,
                     resolveForStart, true /*allowDynamicSplits*/);
+            if (exportedComponentsOnly) {
+                filterNonExportedComponents(intent, filterCallingUid, query,
+                        mPlatformCompat, computer);
+            }
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             final boolean queryMayBeFiltered =
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c0e191f..f7e04d4 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -27,8 +27,8 @@
 import android.util.Xml;
 
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.SharedUserApi;
 
 import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 86affdd..9bd8e12 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -76,9 +76,9 @@
 import com.android.server.SystemConfig;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedActivity;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 98d11bd..e66a72f 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -21,8 +21,8 @@
 import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
 /** A package to be scanned */
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 10e9b54..9037f04 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -102,12 +102,12 @@
 import com.android.server.backup.PreferredActivityBackupHelper;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.permission.LegacyPermissionState;
 import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 7432b84..5905741 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -47,9 +47,9 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.utils.Snappable;
 import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 58be878..fb2ba32 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -26,8 +26,8 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 43dde5c..1da442b 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -53,8 +53,8 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.rollback.RollbackManagerInternal;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 41c6c0f..477e260 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -48,7 +48,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.policy.AttributeCache;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 6847b70..df7e375 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -42,7 +42,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.SuspendParams;
@@ -157,9 +157,11 @@
                 }
             }
 
-            // If size one, the package will be unsuspended from this call
-            boolean packageUnsuspended =
-                    !suspended && CollectionUtils.size(suspendParamsMap) <= 1;
+            // If only the callingPackage is suspending this package,
+            // it will be unsuspended when this change is committed
+            boolean packageUnsuspended = !suspended
+                    && CollectionUtils.size(suspendParamsMap) == 1
+                    && suspendParamsMap.containsKey(callingPackage);
             if (suspended || packageUnsuspended) {
                 changedPackagesList.add(packageName);
                 changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index a1d5054..b620249 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -46,6 +46,15 @@
     public @interface OwnerType {
     }
 
+    // TODO(b/245963156): move to Display.java (and @hide) if we decide to support profiles on MUMD
+    /**
+     * Used only when starting a profile (on systems that
+     * {@link android.os.UserManager#isUsersOnSecondaryDisplaysSupported() support users running on
+     * secondary displays}), to indicate the profile should be started in the same display as its
+     * parent user.
+     */
+    public static final int PARENT_DISPLAY = -2;
+
     public interface UserRestrictionsListener {
         /**
          * Called when a user restriction changes.
@@ -318,6 +327,12 @@
      *
      * <p>On most devices this call will be a no-op, but it will be used on devices that support
      * multiple users on multiple displays (like automotives with passenger displays).
+     *
+     * <p><b>NOTE: </b>this method doesn't validate if the display exists, it's up to the caller to
+     * check it. In fact, one of the intended clients for this method is
+     * {@code DisplayManagerService}, which will call it when a virtual display is created (another
+     * client is {@code UserController}, which will call it when a user is started).
+     *
      */
     public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId);
 
@@ -326,6 +341,9 @@
      *
      * <p>On most devices this call will be a no-op, but it will be used on devices that support
      * multiple users on multiple displays (like automotives with passenger displays).
+     *
+     * <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} (when a user
+     * is stopped) and {@code DisplayManagerService} (when a virtual display is destroyed).
      */
     public abstract void unassignUserFromDisplay(@UserIdInt int userId);
 
@@ -345,10 +363,28 @@
      * Returns the display id assigned to the user, or {@code Display.INVALID_DISPLAY} if the
      * user is not assigned to any display.
      *
-     * <p>The current foreground user is associated with the main display, while other users would
-     * only assigned to a display if they were started with
-     * {@code ActivityManager.startUserInBackgroundOnSecondaryDisplay()}. If the user is a profile
-     * and is running, it's assigned to its parent display.
+     * <p>The current foreground user and its running profiles are associated with the
+     * {@link android.view.Display#DEFAULT_DISPLAY default display}, while other users would only be
+     * assigned to a display if a call to {@link #assignUserToDisplay(int, int)} is made for such
+     * user / display combination (for example, if the user was started with
+     * {@code ActivityManager.startUserInBackgroundOnSecondaryDisplay()}, {@code UserController}
+     * would make such call).
+     *
+     * <p>If the user is a profile and is running, it's assigned to its parent display.
      */
     public abstract int getDisplayAssignedToUser(@UserIdInt int userId);
+
+    /**
+     * Returns the main user (i.e., not a profile) that is assigned to the display, or the
+     * {@link android.app.ActivityManager#getCurrentUser() current foreground user} if no user is
+     * associated with the display.
+     *
+     * <p>The {@link android.view.Display#DEFAULT_DISPLAY default display} is always assigned to
+     * the current foreground user, while other displays would only be associated with users through
+     * a explicit {@link #assignUserToDisplay(int, int)} call with that user / display combination
+     * (for example, if the user was started with
+     * {@code ActivityManager.startUserInBackgroundOnSecondaryDisplay()}, {@code UserController}
+     * would make such call).
+     */
+    public abstract @UserIdInt int getUserAssignedToDisplay(int displayId);
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4bcda2c..3b3e1db 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -630,7 +630,7 @@
     /**
      * Set on on devices that support background users (key) running on secondary displays (value).
      */
-    // TODO(b/239982558): move such logic to a different class (like UserDisplayAssigner)
+    // TODO(b/244644281): move such logic to a different class (like UserDisplayAssigner)
     @Nullable
     @GuardedBy("mUsersOnSecondaryDisplays")
     private final SparseIntArray mUsersOnSecondaryDisplays;
@@ -710,7 +710,8 @@
     @VisibleForTesting
     UserManagerService(Context context) {
         this(context, /* pm= */ null, /* userDataPreparer= */ null,
-                /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null);
+                /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null,
+                /* usersOnSecondaryDisplays= */ null);
     }
 
     /**
@@ -721,13 +722,13 @@
     UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer,
             Object packagesLock) {
         this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory(),
-                /* users= */ null);
+                /* users= */ null, /* usersOnSecondaryDisplays= */ null);
     }
 
     @VisibleForTesting
     UserManagerService(Context context, PackageManagerService pm,
             UserDataPreparer userDataPreparer, Object packagesLock, File dataDir,
-            SparseArray<UserData> users) {
+            SparseArray<UserData> users, @Nullable SparseIntArray usersOnSecondaryDisplays) {
         mContext = context;
         mPm = pm;
         mPackagesLock = packagesLock;
@@ -758,7 +759,13 @@
         mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
         emulateSystemUserModeIfNeeded();
         mUsersOnSecondaryDisplaysEnabled = UserManager.isUsersOnSecondaryDisplaysEnabled();
-        mUsersOnSecondaryDisplays = mUsersOnSecondaryDisplaysEnabled ? new SparseIntArray() : null;
+        if (mUsersOnSecondaryDisplaysEnabled) {
+            mUsersOnSecondaryDisplays = usersOnSecondaryDisplays == null
+                    ? new SparseIntArray() // default behavior
+                    : usersOnSecondaryDisplays; // passed by unit test
+        } else {
+            mUsersOnSecondaryDisplays = null;
+        }
     }
 
     void systemReady() {
@@ -1380,15 +1387,20 @@
     @Override
     public void setUserEnabled(@UserIdInt int userId) {
         checkManageUsersPermission("enable user");
+        UserInfo info;
+        boolean wasUserDisabled = false;
         synchronized (mPackagesLock) {
-            UserInfo info;
             synchronized (mUsersLock) {
                 info = getUserInfoLU(userId);
+                if (info != null && !info.isEnabled()) {
+                    wasUserDisabled = true;
+                    info.flags ^= UserInfo.FLAG_DISABLED;
+                    writeUserLP(getUserDataLU(info.id));
+                }
             }
-            if (info != null && !info.isEnabled()) {
-                info.flags ^= UserInfo.FLAG_DISABLED;
-                writeUserLP(getUserDataLU(info.id));
-            }
+        }
+        if (wasUserDisabled && info != null && info.isProfile()) {
+            sendProfileAddedBroadcast(info.profileGroupId, info.id);
         }
     }
 
@@ -1720,6 +1732,11 @@
         return userId == getCurrentUserId();
     }
 
+    @VisibleForTesting
+    boolean isUsersOnSecondaryDisplaysEnabled() {
+        return mUsersOnSecondaryDisplaysEnabled;
+    }
+
     @Override
     public boolean isUserVisible(@UserIdInt int userId) {
         int callingUserId = UserHandle.getCallingUserId();
@@ -1733,7 +1750,8 @@
         return isUserVisibleUnchecked(userId);
     }
 
-    private boolean isUserVisibleUnchecked(@UserIdInt int userId) {
+    @VisibleForTesting
+    boolean isUserVisibleUnchecked(@UserIdInt int userId) {
         // First check current foreground user and their profiles (on main display)
         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
             return true;
@@ -1750,8 +1768,8 @@
         }
     }
 
-    // TODO(b/239982558): add unit test
-    private int getDisplayAssignedToUser(@UserIdInt int userId) {
+    @VisibleForTesting
+    int getDisplayAssignedToUser(@UserIdInt int userId) {
         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
             return Display.DEFAULT_DISPLAY;
         }
@@ -1765,6 +1783,35 @@
         }
     }
 
+    @VisibleForTesting
+    int getUserAssignedToDisplay(int displayId) {
+        if (displayId == Display.DEFAULT_DISPLAY || !mUsersOnSecondaryDisplaysEnabled) {
+            return getCurrentUserId();
+        }
+
+        synchronized (mUsersOnSecondaryDisplays) {
+            for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
+                if (mUsersOnSecondaryDisplays.valueAt(i) != displayId) {
+                    continue;
+                }
+                int userId = mUsersOnSecondaryDisplays.keyAt(i);
+                if (!isProfileUnchecked(userId)) {
+                    return userId;
+                } else if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
+                            + "a profile", displayId, userId);
+                }
+            }
+        }
+
+        int currentUserId = getCurrentUserId();
+        if (DBG_MUMD) {
+            Slogf.d(LOG_TAG, "getUserAssignedToDisplay(%d): no user assigned to display, returning "
+                    + "current user (%d) instead", displayId, currentUserId);
+        }
+        return currentUserId;
+    }
+
     /**
      * Gets the current user id, calling {@link ActivityManagerInternal} directly (and without
      * performing any permission check).
@@ -1807,22 +1854,48 @@
     }
 
     // TODO(b/239982558): try to merge with isUserVisibleUnchecked() (once both are unit tested)
+    /**
+     * See {@link UserManagerInternal#isUserVisible(int, int)}.
+     */
     boolean isUserVisibleOnDisplay(@UserIdInt int userId, int displayId) {
-        // TODO(b/244644281): temporary workaround to let WM use this API without breaking current
-        // behavior (otherwise current user / profiles wouldn't be able to launch activities on
-        // other non-passenger displays, like cluster, display, or virtual displays)
-        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
-            return true;
+        if (displayId == Display.INVALID_DISPLAY) {
+            return false;
         }
-
-        if (displayId == Display.DEFAULT_DISPLAY) {
+        if (!mUsersOnSecondaryDisplaysEnabled) {
             return isCurrentUserOrRunningProfileOfCurrentUser(userId);
         }
 
-        // Device doesn't support multiple users on multiple displays, so only users checked above
-        // can be visible
-        if (!mUsersOnSecondaryDisplaysEnabled) {
-            return false;
+        // TODO(b/244644281): temporary workaround to let WM use this API without breaking current
+        // behavior - return true for current user / profile for any display (other than those
+        // explicitly assigned to another users), otherwise they wouldn't be able to launch
+        // activities on other non-passenger displays, like cluster, display, or virtual displays).
+        // In the long-term, it should rely just on mUsersOnSecondaryDisplays, which
+        // would be updated by DisplayManagerService when displays are created / initialized.
+        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
+            synchronized (mUsersOnSecondaryDisplays) {
+                boolean assignedToUser = false;
+                boolean assignedToAnotherUser = false;
+                for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
+                    if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
+                        if (mUsersOnSecondaryDisplays.keyAt(i) == userId) {
+                            assignedToUser = true;
+                            break;
+                        } else {
+                            assignedToAnotherUser = true;
+                            // Cannot break because it could be assigned to a profile of the user
+                            // (and we better not assume that the iteration will check for the
+                            // parent user before its profiles)
+                        }
+                    }
+                }
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "isUserVisibleOnDisplay(%d, %d): assignedToUser=%b, "
+                            + "assignedToAnotherUser=%b, mUsersOnSecondaryDisplays=%s",
+                            userId, displayId, assignedToUser, assignedToAnotherUser,
+                            mUsersOnSecondaryDisplays);
+                }
+                return assignedToUser || !assignedToAnotherUser;
+            }
         }
 
         synchronized (mUsersOnSecondaryDisplays) {
@@ -4817,7 +4890,9 @@
         MetricsLogger.count(mContext, userInfo.isGuest() ? TRON_GUEST_CREATED
                 : (userInfo.isDemo() ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1);
 
-        if (!userInfo.isProfile()) {
+        if (userInfo.isProfile()) {
+            sendProfileAddedBroadcast(userInfo.profileGroupId, userInfo.id);
+        } else {
             // If the user switch hasn't been explicitly toggled on or off by the user, turn it on.
             if (android.provider.Settings.Global.getString(mContext.getContentResolver(),
                     android.provider.Settings.Global.USER_SWITCHER_ENABLED) == null) {
@@ -5417,6 +5492,17 @@
     }
 
     /**
+     * Send {@link Intent#ACTION_PROFILE_ADDED} broadcast when a user of type
+     * {@link UserInfo#isProfile()} is added. This broadcast is sent only to dynamic receivers
+     * created with {@link Context#registerReceiver}.
+     */
+    private void sendProfileAddedBroadcast(int parentUserId, int addedUserId) {
+        sendProfileBroadcast(
+                new Intent(Intent.ACTION_PROFILE_ADDED),
+                parentUserId, addedUserId);
+    }
+
+    /**
      * Send {@link Intent#ACTION_PROFILE_REMOVED} broadcast when a user of type
      * {@link UserInfo#isProfile()} is removed. Additionally sends
      * {@link Intent#ACTION_MANAGED_PROFILE_REMOVED} broadcast if the profile is of type
@@ -5434,12 +5520,12 @@
         if (Objects.equals(userType, UserManager.USER_TYPE_PROFILE_MANAGED)) {
             sendManagedProfileRemovedBroadcast(parentUserId, removedUserId);
         }
-        sendProfileBroadcastToRegisteredReceivers(
+        sendProfileBroadcast(
                 new Intent(Intent.ACTION_PROFILE_REMOVED),
                 parentUserId, removedUserId);
     }
 
-    private void sendProfileBroadcastToRegisteredReceivers(Intent intent,
+    private void sendProfileBroadcast(Intent intent,
             int parentUserId, int userId) {
         final UserHandle parentHandle = UserHandle.of(parentUserId);
         intent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
@@ -5450,7 +5536,7 @@
 
     private void sendManagedProfileRemovedBroadcast(int parentUserId, int removedUserId) {
         Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
+        managedProfileIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(removedUserId));
         managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId);
         final UserHandle parentHandle = UserHandle.of(parentUserId);
         getDevicePolicyManagerInternal().broadcastIntentToManifestReceivers(
@@ -6510,9 +6596,14 @@
 
         @Override
         public boolean isUserRunning(@UserIdInt int userId) {
+            int state;
             synchronized (mUserStates) {
-                return mUserStates.get(userId, -1) >= 0;
+                state =  mUserStates.get(userId, UserState.STATE_NONE);
             }
+
+            return state != UserState.STATE_NONE
+                    && state != UserState.STATE_STOPPING
+                    && state != UserState.STATE_SHUTDOWN;
         }
 
         @Override
@@ -6719,46 +6810,53 @@
                         + "users on multiple displays");
             }
 
-            Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot start system user"
-                    + " on secondary display (%d)", displayId);
-            // TODO(b/239982558): call DisplayManagerInternal to check if display is valid instead
-            Preconditions.checkArgument(displayId > 0, "Invalid display id (%d)", displayId);
+            Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot assign system "
+                    + "user to secondary display (%d)", displayId);
+            Preconditions.checkArgument(displayId != Display.INVALID_DISPLAY,
+                    "Cannot assign to INVALID_DISPLAY (%d)", displayId);
+
+            int currentUserId = getCurrentUserId();
+            Preconditions.checkArgument(userId != currentUserId,
+                    "Cannot assign current user (%d) to other displays", currentUserId);
 
             synchronized (mUsersOnSecondaryDisplays) {
-                if (DBG_MUMD) {
-                    Slogf.d(LOG_TAG, "Adding %d->%d to mUsersOnSecondaryDisplays",
-                            userId, displayId);
-                }
-
                 if (isProfileUnchecked(userId)) {
                     // Profile can only start in the same display as parent
+                    Preconditions.checkArgument(displayId == UserManagerInternal.PARENT_DISPLAY,
+                            "Profile user can only be started in the same display as parent");
                     int parentUserId = getProfileParentId(userId);
                     int parentDisplayId = mUsersOnSecondaryDisplays.get(parentUserId);
-                    if (displayId != parentDisplayId) {
-                        throw new IllegalStateException("Cannot assign profile " + userId + " to "
-                                + "display " + displayId + " as its parent (user " + parentUserId
-                                + ") is assigned to display " + parentDisplayId);
+                    if (DBG_MUMD) {
+                        Slogf.d(LOG_TAG, "Adding profile user %d -> display %d", userId,
+                                parentDisplayId);
                     }
-                } else {
-                    // Check if display is available
-                    for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
-                        // Make sure display is not used by other users...
-                        // TODO(b/240736142); currently, if a user was started in a display, it
-                        // would need to be stopped first, so "switching" a user on secondary
-                        // diplay requires 2 non-atomic operations (stop and start). Once this logic
-                        // is refactored, it should be atomic.
-                        if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
-                            throw new IllegalStateException("Cannot assign " + userId + " to "
-                                    + "display " + displayId + " as it's  already assigned to "
-                                    + "user " + mUsersOnSecondaryDisplays.keyAt(i));
-                        }
-                        // TODO(b/239982558) also check that user is not already assigned to other
-                        // display (including 0). That would be harder to tested under CTS though
-                        // (for example, would need to add a new AM method to start user in bg on
-                        // main display), so it's better to test on unit tests
+                    mUsersOnSecondaryDisplays.put(userId, parentDisplayId);
+                    return;
+                }
+
+                // Check if display is available
+                for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
+                    int assignedUserId = mUsersOnSecondaryDisplays.keyAt(i);
+                    int assignedDisplayId = mUsersOnSecondaryDisplays.valueAt(i);
+                    if (DBG_MUMD) {
+                        Slogf.d(LOG_TAG, "%d: assignedUserId=%d, assignedDisplayId=%d",
+                                i, assignedUserId, assignedDisplayId);
+                    }
+                    if (displayId == assignedDisplayId) {
+                        throw new IllegalStateException("Cannot assign user " + userId + " to "
+                                + "display " + displayId + " because such display is already "
+                                + "assigned to user " + assignedUserId);
+                    }
+                    if (userId == assignedUserId) {
+                        throw new IllegalStateException("Cannot assign user " + userId + " to "
+                                + "display " + displayId + " because such user is as already "
+                                + "assigned to display " + assignedDisplayId);
                     }
                 }
 
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "Adding full user %d -> display %d", userId, displayId);
+                }
                 mUsersOnSecondaryDisplays.put(userId, displayId);
             }
         }
@@ -6800,6 +6898,11 @@
         public int getDisplayAssignedToUser(int userId) {
             return UserManagerService.this.getDisplayAssignedToUser(userId);
         }
+
+        @Override
+        public int getUserAssignedToDisplay(int displayId) {
+            return UserManagerService.this.getUserAssignedToDisplay(displayId);
+        }
     } // class LocalService
 
     /**
diff --git a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
index 8f13f7a..6e86123 100644
--- a/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/pm/UserManagerServiceShellCommand.java
@@ -35,7 +35,6 @@
 import android.os.UserManager;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
-import android.view.Display;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -374,21 +373,16 @@
     })
     private int runIsUserVisible() {
         PrintWriter pw = getOutPrintWriter();
-        int displayId = Display.INVALID_DISPLAY;
+        Integer displayId = null;
         String opt;
         while ((opt = getNextOption()) != null) {
-            boolean invalidOption = false;
             switch (opt) {
                 case "--display":
                     displayId = Integer.parseInt(getNextArgRequired());
-                    invalidOption = displayId == Display.INVALID_DISPLAY;
                     break;
                 default:
-                    invalidOption = true;
-            }
-            if (invalidOption) {
-                pw.println("Invalid option: " + opt);
-                return -1;
+                    pw.println("Invalid option: " + opt);
+                    return -1;
             }
         }
         int userId = UserHandle.parseUserArg(getNextArgRequired());
@@ -404,7 +398,7 @@
         }
 
         boolean isVisible;
-        if (displayId != Display.INVALID_DISPLAY) {
+        if (displayId != null) {
             isVisible = mService.isUserVisibleOnDisplay(userId, displayId);
         } else {
             isVisible = getUserManagerForUser(userId).isUserVisible();
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index b57d4d5..2d876ed 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -35,7 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.lang.annotation.Retention;
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index cca3b35..6bc323e 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -54,7 +54,7 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageManagerServiceCompilerMapping;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import dalvik.system.DexFile;
 import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/dex/ArtUtils.java b/services/core/java/com/android/server/pm/dex/ArtUtils.java
index 068a064..77aefc5c 100644
--- a/services/core/java/com/android/server/pm/dex/ArtUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtUtils.java
@@ -21,8 +21,8 @@
 import android.annotation.NonNull;
 
 import com.android.server.pm.PackageDexOptimizer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index beea86d..5ba209d 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -23,7 +23,7 @@
 
 import com.android.internal.os.ClassLoaderFactory;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index ee66a5586..9ce648f 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -23,7 +23,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.pm.Installer;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 5be81d5..1084145 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -54,9 +54,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUnserialized;
 import com.android.server.pm.pkg.PackageUserState;
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
index c67d0d2..7031dc3 100644
--- a/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -28,9 +28,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.IPlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * Updates a package to ensure that if it targets <= Q that the android.test.base library is
diff --git a/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
index 7de457e..96fead2 100644
--- a/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
+++ b/services/core/java/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -20,8 +20,8 @@
 import android.os.Build;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
similarity index 86%
rename from services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
rename to services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
index b314fe2..8d43fe7 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageInternal.java
@@ -17,7 +17,7 @@
 package com.android.server.pm.parsing.pkg;
 
 import com.android.internal.content.om.OverlayConfig;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 
 /**
  * The last state of a package during parsing/install before it is available in {@link
@@ -29,6 +29,7 @@
  *
  * @hide
  */
-public interface AndroidPackage extends AndroidPackageApi, OverlayConfig.PackageProvider.Package {
+public interface AndroidPackageInternal extends AndroidPackage,
+        OverlayConfig.PackageProvider.Package {
 
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 76bae37..f6585f6 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -33,7 +33,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemConfig;
 import com.android.server.pm.PackageManagerException;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
@@ -340,7 +340,7 @@
         info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
     }
 
-    public static ApplicationInfo toAppInfoWithoutState(AndroidPackageApi pkg) {
+    public static ApplicationInfo toAppInfoWithoutState(AndroidPackage pkg) {
         return ((ParsingPackageHidden) pkg).toAppInfoWithoutState();
     }
 }
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 11fb78f..70aca99 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -56,6 +56,7 @@
 import com.android.internal.util.Parcelling;
 import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
 import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedActivity;
@@ -102,7 +103,7 @@
  *
  * @hide
  */
-public class PackageImpl implements ParsedPackage, AndroidPackage,
+public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
         AndroidPackageHidden, ParsingPackage, ParsingPackageHidden, Parcelable {
 
     private static final SparseArray<int[]> EMPTY_INT_ARRAY_SPARSE_ARRAY = new SparseArray<>();
@@ -2591,7 +2592,7 @@
     }
 
     @Override
-    public AndroidPackage hideAsFinal() {
+    public AndroidPackageInternal hideAsFinal() {
         // TODO(b/135203078): Lock as immutable
         if (mStorageUuid == null) {
             assignDerivedFields();
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index 38d87e2..d306341 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -18,17 +18,22 @@
 
 import android.content.pm.SigningDetails;
 
+import com.android.server.pm.pkg.AndroidPackage;
+
 /**
  * Methods used for mutation after direct package parsing, mostly done inside
  * {@link com.android.server.pm.PackageManagerService}.
  *
  * Java disallows defining this as an inner interface, so this must be a separate file.
  *
+ * TODO: Remove extending AndroidPackage, should be an isolated interface with only the methods
+ *  necessary to parse and install
+ *
  * @hide
  */
 public interface ParsedPackage extends AndroidPackage {
 
-    AndroidPackage hideAsFinal();
+    AndroidPackageInternal hideAsFinal();
 
     ParsedPackage addUsesLibrary(int index, String libraryName);
 
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
index 88b4a94..23872d4f 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
@@ -46,7 +46,7 @@
  * Legacy permission manager service.
  */
 public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stub {
-    private static final String TAG = "PackageManager";
+    private static final String TAG = "PermissionManager";
 
     /** Injector that can be used to facilitate testing. */
     private final Injector mInjector;
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index d5456e3..69e7bf1 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -23,14 +23,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
-import com.android.server.pm.pkg.component.ParsedPermission;
 import android.os.Build;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedPermission;
 
 import libcore.util.EmptyArray;
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3df412d..3b9f0ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -72,8 +72,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index c05d5ce..4a80c4a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -131,9 +131,8 @@
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.component.ComponentMutateUtils;
 import com.android.server.pm.pkg.component.ParsedPermission;
@@ -168,7 +167,7 @@
  */
 public class PermissionManagerServiceImpl implements PermissionManagerServiceInterface {
 
-    private static final String TAG = "PackageManager";
+    private static final String TAG = "PermissionManager";
     private static final String LOG_TAG = PermissionManagerServiceImpl.class.getSimpleName();
 
     private static final String SKIP_KILL_APP_REASON_NOTIFICATION_TEST = "skip permission revoke "
@@ -2612,7 +2611,7 @@
                     mPackageManagerInt.getSharedUserPackages(ps.getSharedUserAppId());
             int packagesSize = packages.size();
             for (int i = 0; i < packagesSize; i++) {
-                AndroidPackageApi sharedUserPackage =
+                AndroidPackage sharedUserPackage =
                         packages.valueAt(i).getAndroidPackage();
                 if (sharedUserPackage == null) {
                     continue;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 02d184e..930936b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,9 +25,10 @@
 import android.content.pm.PermissionInfo;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 2d5ec39..f20620e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -23,7 +23,7 @@
 import android.content.pm.PermissionInfo;
 import android.permission.PermissionManagerInternal;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
similarity index 99%
rename from services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
rename to services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index a454bcd..6078d4a 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackageApi.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -40,7 +40,6 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.R;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedApexSystemService;
 import com.android.server.pm.pkg.component.ParsedAttribution;
@@ -66,7 +65,7 @@
  * @hide
  */
 //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-public interface AndroidPackageApi {
+public interface AndroidPackage {
 
     /**
      * @see ApplicationInfo#areAttributionsUserVisible()
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index b5e0e44..f0e386c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -74,7 +74,7 @@
      * app once the device reboots or otherwise re-scans it.
      */
     @Nullable
-    AndroidPackageApi getAndroidPackage();
+    AndroidPackage getAndroidPackage();
 
     /**
      * The non-user-specific UID, or the UID if the user ID is
@@ -86,7 +86,7 @@
      * Value set through {@link PackageManager#setApplicationCategoryHint(String, int)}. Only
      * applied if the application itself does not declare a category.
      *
-     * @see AndroidPackageApi#getCategory()
+     * @see AndroidPackage#getCategory()
      */
     int getCategoryOverride();
 
@@ -121,7 +121,7 @@
 
     /**
      * Cached here in case the physical code directory on device is unmounted.
-     * @see AndroidPackageApi#getLongVersionCode()
+     * @see AndroidPackage#getLongVersionCode()
      */
     long getVersionCode();
 
@@ -134,14 +134,14 @@
     Map<String, Set<String>> getMimeGroups();
 
     /**
-     * @see AndroidPackageApi#getPackageName()
+     * @see AndroidPackage#getPackageName()
      */
     @NonNull
     String getPackageName();
 
     /**
      * TODO: Rename this to getCodePath
-     * @see AndroidPackageApi#getPath()
+     * @see AndroidPackage#getPath()
      */
     @NonNull
     File getPath();
@@ -227,13 +227,13 @@
     long[] getUsesStaticLibrariesVersions();
 
     /**
-     * @see AndroidPackageApi#getVolumeUuid()
+     * @see AndroidPackage#getVolumeUuid()
      */
     @Nullable
     String getVolumeUuid();
 
     /**
-     * @see AndroidPackageApi#isExternalStorage()
+     * @see AndroidPackage#isExternalStorage()
      */
     boolean isExternalStorage();
 
@@ -257,22 +257,22 @@
     boolean isInstallPermissionsFixed();
 
     /**
-     * @see AndroidPackageApi#isOdm()
+     * @see AndroidPackage#isOdm()
      */
     boolean isOdm();
 
     /**
-     * @see AndroidPackageApi#isOem()
+     * @see AndroidPackage#isOem()
      */
     boolean isOem();
 
     /**
-     * @see AndroidPackageApi#isPrivileged()
+     * @see AndroidPackage#isPrivileged()
      */
     boolean isPrivileged();
 
     /**
-     * @see AndroidPackageApi#isProduct()
+     * @see AndroidPackage#isProduct()
      */
     boolean isProduct();
 
@@ -282,12 +282,12 @@
     boolean isRequiredForSystemUser();
 
     /**
-     * @see AndroidPackageApi#isSystem()
+     * @see AndroidPackage#isSystem()
      */
     boolean isSystem();
 
     /**
-     * @see AndroidPackageApi#isSystemExt()
+     * @see AndroidPackage#isSystemExt()
      */
     boolean isSystemExt();
 
@@ -308,7 +308,7 @@
     boolean isApkInUpdatedApex();
 
     /**
-     * @see AndroidPackageApi#isVendor()
+     * @see AndroidPackage#isVendor()
      */
     boolean isVendor();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index 878a837..eac0842 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -31,7 +31,6 @@
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.Settings;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
@@ -108,7 +107,7 @@
     }
 
     @Nullable
-    private final AndroidPackageApi mAndroidPackage;
+    private final AndroidPackage mAndroidPackage;
 
     @NonNull
     private final String mPackageName;
@@ -570,7 +569,7 @@
     }
 
     @DataClass.Generated.Member
-    public @Nullable AndroidPackageApi getAndroidPackage() {
+    public @Nullable AndroidPackage getAndroidPackage() {
         return mAndroidPackage;
     }
 
@@ -694,7 +693,7 @@
             time = 1644270981543L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
-            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackageApi mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> mUsesLibraryInfos\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index 68a00a9..84799ea 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -24,7 +24,7 @@
 
 import com.android.server.pm.InstallSource;
 import com.android.server.pm.PackageKeySetData;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal;
 import com.android.server.pm.permission.LegacyPermissionState;
 
 import java.util.UUID;
@@ -35,7 +35,7 @@
 public interface PackageStateInternal extends PackageState {
 
     @NonNull
-    AndroidPackage getPkg();
+    AndroidPackageInternal getPkg();
 
     // TODO: Remove in favor of exposing APIs directly?
     @NonNull
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
index 91e9b2f..a883a05 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
@@ -20,11 +20,9 @@
 import android.annotation.Nullable;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
-
 import android.util.SparseArray;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
 
 public class PackageStateUtils {
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
index 3bdebd1..15e3d0c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
@@ -26,7 +26,6 @@
 import android.util.DebugUtils;
 import android.util.Slog;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
 
 /** @hide */
diff --git a/services/core/java/com/android/server/pm/pkg/SharedUserApi.java b/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
index 94a87f3..55c305c 100644
--- a/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
+++ b/services/core/java/com/android/server/pm/pkg/SharedUserApi.java
@@ -22,7 +22,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.LegacyPermissionState;
 import com.android.server.pm.pkg.component.ParsedProcess;
 
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index 7baec62..a19beea 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -51,7 +51,7 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.UserNeedsBadgingCache;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
@@ -930,12 +930,14 @@
         }
 
         @Override
-        protected boolean isFilterStopped(@Nullable PackageStateInternal packageState,
+        protected boolean isFilterStopped(@NonNull Computer computer, F filter,
                 @UserIdInt int userId) {
             if (!mUserManager.exists(userId)) {
                 return true;
             }
 
+            final PackageStateInternal packageState = computer.getPackageStateInternal(
+                    filter.first.getPackageName());
             if (packageState == null || packageState.getPkg() == null) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
index c01cecf..75d7162 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolverBase.java
@@ -32,8 +32,8 @@
 import com.android.server.pm.DumpState;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.component.ParsedActivity;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index e078120..adef808 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -22,8 +22,6 @@
 import android.compat.annotation.EnabledSince;
 import android.content.Intent;
 import android.content.IntentFilter;
-import com.android.server.pm.pkg.component.ParsedActivity;
-import com.android.server.pm.pkg.component.ParsedIntentInfo;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -31,7 +29,9 @@
 
 import com.android.server.SystemConfig;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
 
 import java.util.List;
 import java.util.Objects;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index e06b608..d67613c 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -31,7 +31,7 @@
 
 import com.android.internal.util.CollectionUtils;
 import com.android.server.pm.Computer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 3cd7795..400af36 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -55,7 +55,7 @@
 import com.android.server.SystemService;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.Computer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
 import com.android.server.pm.pkg.PackageUserStateInternal;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
index 8d1ae0b..cde72cd 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
@@ -29,7 +29,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.Computer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
index 058b605..3fd00c6 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationUtils.java
@@ -28,7 +28,7 @@
 import com.android.internal.util.CollectionUtils;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Set;
 import java.util.regex.Matcher;
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index c8e46b6..752eb53 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -39,7 +39,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.verify.domain.DomainVerificationCollector;
 import com.android.server.pm.verify.domain.DomainVerificationDebug;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 7602d33..ffb652e 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -96,8 +96,8 @@
 import com.android.server.SystemService;
 import com.android.server.notification.NotificationManagerInternal;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
 import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.wm.ActivityInterceptorCallback;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1bb476f..675819a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2930,6 +2930,11 @@
                             UserHandle.CURRENT_OR_SELF);
                 }
                 return key_consumed;
+            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
+            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
+            case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
+                // TODO: Add logic to handle keyboard backlight controls (go/pk_backlight_control)
+                return key_consumed;
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_MUTE:
@@ -3047,6 +3052,13 @@
                     }
                 }
                 break;
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY:
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL:
+                Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in"
+                        + " interceptKeyBeforeQueueing");
+                return key_consumed;
         }
 
         if (isValidGlobalKey(keyCode)
@@ -4099,6 +4111,14 @@
                 result &= ~ACTION_PASS_TO_USER;
                 break;
             }
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY:
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
+            case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL: {
+                // TODO(go/android-stylus-buttons): Handle stylus button presses.
+                result &= ~ACTION_PASS_TO_USER;
+                break;
+            }
         }
 
         if (useHapticFeedback) {
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index ab71355..33fc6fb 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -42,7 +42,7 @@
 import android.provider.DeviceConfig;
 
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.Arrays;
 import java.util.HashSet;
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5a2fb18..dad9584 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -571,7 +571,8 @@
     /**
      * Called when there has been user activity.
      */
-    public void onUserActivity(int displayGroupId, int event, int uid) {
+    public void onUserActivity(int displayGroupId, @PowerManager.UserActivityEvent int event,
+            int uid) {
         if (DEBUG) {
             Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
         }
diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java
index fec61ac..9fe53fb 100644
--- a/services/core/java/com/android/server/power/PowerGroup.java
+++ b/services/core/java/com/android/server/power/PowerGroup.java
@@ -74,6 +74,8 @@
     private long mLastPowerOnTime;
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
+    @PowerManager.UserActivityEvent
+    private int mLastUserActivityEvent;
     /** Timestamp (milliseconds since boot) of the last time the power group was awoken.*/
     private long mLastWakeTime;
     /** Timestamp (milliseconds since boot) of the last time the power group was put to sleep. */
@@ -244,7 +246,7 @@
         return true;
     }
 
-    boolean dozeLocked(long eventTime, int uid, int reason) {
+    boolean dozeLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
         if (eventTime < getLastWakeTimeLocked() || !isInteractive(mWakefulness)) {
             return false;
         }
@@ -253,9 +255,14 @@
         try {
             reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
                     Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
+            long millisSinceLastUserActivity = eventTime - Math.max(
+                    mLastUserActivityTimeNoChangeLights, mLastUserActivityTime);
             Slog.i(TAG, "Powering off display group due to "
-                    + PowerManager.sleepReasonToString(reason)  + " (groupId= " + getGroupId()
-                    + ", uid= " + uid + ")...");
+                    + PowerManager.sleepReasonToString(reason)
+                    + " (groupId= " + getGroupId() + ", uid= " + uid
+                    + ", millisSinceLastUserActivity=" + millisSinceLastUserActivity
+                    + ", lastUserActivityEvent=" + PowerManager.userActivityEventToString(
+                    mLastUserActivityEvent) + ")...");
 
             setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
             setWakefulnessLocked(WAKEFULNESS_DOZING, eventTime, uid, reason, /* opUid= */ 0,
@@ -266,14 +273,16 @@
         return true;
     }
 
-    boolean sleepLocked(long eventTime, int uid, int reason) {
+    boolean sleepLocked(long eventTime, int uid, @PowerManager.GoToSleepReason int reason) {
         if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
             return false;
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "sleepPowerGroup");
         try {
-            Slog.i(TAG, "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ")...");
+            Slog.i(TAG,
+                    "Sleeping power group (groupId=" + getGroupId() + ", uid=" + uid + ", reason="
+                            + PowerManager.sleepReasonToString(reason) + ")...");
             setSandmanSummonedLocked(/* isSandmanSummoned= */ true);
             setWakefulnessLocked(WAKEFULNESS_ASLEEP, eventTime, uid, reason, /* opUid= */0,
                     /* opPackageName= */ null, /* details= */ null);
@@ -287,16 +296,20 @@
         return mLastUserActivityTime;
     }
 
-    void setLastUserActivityTimeLocked(long lastUserActivityTime) {
+    void setLastUserActivityTimeLocked(long lastUserActivityTime,
+            @PowerManager.UserActivityEvent int event) {
         mLastUserActivityTime = lastUserActivityTime;
+        mLastUserActivityEvent = event;
     }
 
     public long getLastUserActivityTimeNoChangeLightsLocked() {
         return mLastUserActivityTimeNoChangeLights;
     }
 
-    public void setLastUserActivityTimeNoChangeLightsLocked(long time) {
+    public void setLastUserActivityTimeNoChangeLightsLocked(long time,
+            @PowerManager.UserActivityEvent int event) {
         mLastUserActivityTimeNoChangeLights = time;
+        mLastUserActivityEvent = event;
     }
 
     public int getUserActivitySummaryLocked() {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9ee0df9..2d22b8f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1216,6 +1216,7 @@
                 return;
             }
 
+            Slog.i(TAG, "onFlip(): Face " + (isFaceDown ? "down." : "up."));
             mIsFaceDown = isFaceDown;
             if (isFaceDown) {
                 final long currentTime = mClock.uptimeMillis();
@@ -1937,12 +1938,13 @@
 
     // Called from native code.
     @SuppressWarnings("unused")
-    private void userActivityFromNative(long eventTime, int event, int displayId, int flags) {
+    private void userActivityFromNative(long eventTime, @PowerManager.UserActivityEvent int event,
+            int displayId, int flags) {
         userActivityInternal(displayId, eventTime, event, flags, Process.SYSTEM_UID);
     }
 
-    private void userActivityInternal(int displayId, long eventTime, int event, int flags,
-            int uid) {
+    private void userActivityInternal(int displayId, long eventTime,
+            @PowerManager.UserActivityEvent int event, int flags, int uid) {
         synchronized (mLock) {
             if (displayId == Display.INVALID_DISPLAY) {
                 if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
@@ -1993,11 +1995,12 @@
 
     @GuardedBy("mLock")
     private boolean userActivityNoUpdateLocked(final PowerGroup powerGroup, long eventTime,
-            int event, int flags, int uid) {
+            @PowerManager.UserActivityEvent int event, int flags, int uid) {
         final int groupId = powerGroup.getGroupId();
         if (DEBUG_SPEW) {
             Slog.d(TAG, "userActivityNoUpdateLocked: groupId=" + groupId
-                    + ", eventTime=" + eventTime + ", event=" + event
+                    + ", eventTime=" + eventTime
+                    + ", event=" + PowerManager.userActivityEventToString(event)
                     + ", flags=0x" + Integer.toHexString(flags) + ", uid=" + uid);
         }
 
@@ -2032,7 +2035,7 @@
             if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
                 if (eventTime > powerGroup.getLastUserActivityTimeNoChangeLightsLocked()
                         && eventTime > powerGroup.getLastUserActivityTimeLocked()) {
-                    powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime);
+                    powerGroup.setLastUserActivityTimeNoChangeLightsLocked(eventTime, event);
                     mDirty |= DIRTY_USER_ACTIVITY;
                     if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                         mDirty |= DIRTY_QUIESCENT;
@@ -2042,7 +2045,7 @@
                 }
             } else {
                 if (eventTime > powerGroup.getLastUserActivityTimeLocked()) {
-                    powerGroup.setLastUserActivityTimeLocked(eventTime);
+                    powerGroup.setLastUserActivityTimeLocked(eventTime, event);
                     mDirty |= DIRTY_USER_ACTIVITY;
                     if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                         mDirty |= DIRTY_QUIESCENT;
@@ -2069,7 +2072,8 @@
             @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "wakePowerGroupLocked: eventTime=" + eventTime
-                    + ", groupId=" + powerGroup.getGroupId() + ", uid=" + uid);
+                    + ", groupId=" + powerGroup.getGroupId()
+                    + ", reason=" + PowerManager.wakeReasonToString(reason) + ", uid=" + uid);
         }
         if (mForceSuspendActive || !mSystemReady) {
             return;
@@ -2092,11 +2096,11 @@
 
     @GuardedBy("mLock")
     private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime,
-            int reason, int uid) {
+            @GoToSleepReason int reason, int uid) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "dozePowerGroup: eventTime=" + eventTime
-                    + ", groupId=" + powerGroup.getGroupId() + ", reason=" + reason
-                    + ", uid=" + uid);
+                    + ", groupId=" + powerGroup.getGroupId()
+                    + ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
         }
 
         if (!mSystemReady || !mBootCompleted) {
@@ -2107,10 +2111,12 @@
     }
 
     @GuardedBy("mLock")
-    private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime, int reason,
-            int uid) {
+    private boolean sleepPowerGroupLocked(final PowerGroup powerGroup, long eventTime,
+            @GoToSleepReason int reason, int uid) {
         if (DEBUG_SPEW) {
-            Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime + ", uid=" + uid);
+            Slog.d(TAG, "sleepPowerGroup: eventTime=" + eventTime
+                    + ", groupId=" + powerGroup.getGroupId()
+                    + ", reason=" + PowerManager.sleepReasonToString(reason) + ", uid=" + uid);
         }
         if (!mBootCompleted || !mSystemReady) {
             return false;
@@ -2172,7 +2178,10 @@
             case WAKEFULNESS_DOZING:
                 traceMethodName = "goToSleep";
                 Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
-                        + " (uid " + uid + ")...");
+                        + " (uid " + uid + ", screenOffTimeout=" + mScreenOffTimeoutSetting
+                        + ", activityTimeoutWM=" + mUserActivityTimeoutOverrideFromWindowManager
+                        + ", maxDimRatio=" + mMaximumScreenDimRatioConfig
+                        + ", maxDimDur=" + mMaximumScreenDimDurationConfig + ")...");
                 mLastGlobalSleepTime = eventTime;
                 mLastGlobalSleepReason = reason;
                 mLastGlobalSleepTimeRealtime = mClock.elapsedRealtime();
@@ -4258,7 +4267,7 @@
     void onUserActivity() {
         synchronized (mLock) {
             mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).setLastUserActivityTimeLocked(
-                    mClock.uptimeMillis());
+                    mClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER);
         }
     }
 
@@ -5646,7 +5655,8 @@
         }
 
         @Override // Binder call
-        public void userActivity(int displayId, long eventTime, int event, int flags) {
+        public void userActivity(int displayId, long eventTime,
+                @PowerManager.UserActivityEvent int event, int flags) {
             final long now = mClock.uptimeMillis();
             if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
                     != PackageManager.PERMISSION_GRANTED
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 5fdd006..c6128f9 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -178,7 +178,7 @@
     // TODO: remove "tcp" from network methods, since we measure total stats.
 
     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
-    public static final int VERSION = 209;
+    public static final int VERSION = 210;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -5413,7 +5413,8 @@
     }
 
     @GuardedBy("this")
-    public void noteUserActivityLocked(int uid, int event, long elapsedRealtimeMs, long uptimeMs) {
+    public void noteUserActivityLocked(int uid, @PowerManager.UserActivityEvent int event,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (mOnBatteryInternal) {
             uid = mapUid(uid);
             getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteUserActivityLocked(event);
@@ -8846,14 +8847,14 @@
         }
 
         @Override
-        public void noteUserActivityLocked(int type) {
+        public void noteUserActivityLocked(@PowerManager.UserActivityEvent int event) {
             if (mUserActivityCounters == null) {
                 initUserActivityLocked();
             }
-            if (type >= 0 && type < NUM_USER_ACTIVITY_TYPES) {
-                mUserActivityCounters[type].stepAtomic();
+            if (event >= 0 && event < NUM_USER_ACTIVITY_TYPES) {
+                mUserActivityCounters[event].stepAtomic();
             } else {
-                Slog.w(TAG, "Unknown user activity type " + type + " was specified.",
+                Slog.w(TAG, "Unknown user activity type " + event + " was specified.",
                         new Throwable());
             }
         }
@@ -14965,6 +14966,18 @@
         }
     }
 
+    @GuardedBy("this")
+    private void dumpCpuPowerBracketsLocked(PrintWriter pw) {
+        pw.println("CPU power brackets; cluster/freq in MHz(avg current in mA):");
+        final int bracketCount = mPowerProfile.getCpuPowerBracketCount();
+        for (int bracket = 0; bracket < bracketCount; bracket++) {
+            pw.print("    ");
+            pw.print(bracket);
+            pw.print(": ");
+            pw.println(mPowerProfile.getCpuPowerBracketDescription(bracket));
+        }
+    }
+
     /**
      * Dump measured charge stats
      */
@@ -16297,6 +16310,9 @@
         dumpConstantsLocked(pw);
 
         pw.println();
+        dumpCpuPowerBracketsLocked(pw);
+
+        pw.println();
         dumpMeasuredEnergyStatsLocked(pw);
     }
 
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 38e6b28..85d93f4 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -52,7 +52,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.RescueParty;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 05d92be..b0f03ef 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -17,6 +17,7 @@
 package com.android.server.soundtrigger_middleware;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.media.soundtrigger.ModelParameterRange;
 import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
@@ -289,43 +290,60 @@
      * they were pushed.
      * <li>Events can be flushed via {@link #flush()}. This will block until all events pushed prior
      * to this call have been fully processed.
+     * TODO(b/246584464) Remove and replace with Handler (and other concurrency fixes).
      * </ul>
      */
-    private static class CallbackThread {
+    private static class CallbackThread implements Runnable {
         private final Queue<Runnable> mList = new LinkedList<>();
         private int mPushCount = 0;
         private int mProcessedCount = 0;
-
+        private boolean mQuitting = false;
+        private final Thread mThread;
         /**
          * Ctor. Starts the thread.
          */
         CallbackThread() {
-            new Thread(() -> {
-                try {
-                    while (true) {
-                        pop().run();
-                        synchronized (mList) {
-                            mProcessedCount++;
-                            mList.notifyAll();
-                        }
-                    }
-                } catch (InterruptedException e) {
-                    // If interrupted, exit.
-                }
-            }).start();
+            mThread = new Thread(this , "STHAL Concurrent Capture Handler Callback");
+            mThread.start();
         }
-
+        /**
+         * Consume items in the queue until quit is called.
+         */
+        public void run() {
+            try {
+                while (true) {
+                    Runnable toRun = pop();
+                    if (toRun == null) {
+                      // There are no longer any runnables to run,
+                      // and quit() has been called.
+                      return;
+                    }
+                    toRun.run();
+                    synchronized (mList) {
+                        mProcessedCount++;
+                        mList.notifyAll();
+                    }
+                }
+            } catch (InterruptedException e) {
+                // If interrupted, exit.
+                // Note, this is dangerous wrt to flush.
+            }
+        }
         /**
          * Push a new runnable to the queue, with no deduping.
+         * If quit has been called, the runnable will not be pushed.
          *
          * @param runnable The runnable to push.
+         * @return If the runnable was successfully pushed.
          */
-        void push(Runnable runnable) {
+        boolean push(Runnable runnable) {
             synchronized (mList) {
+                if (mQuitting) return false;
                 mList.add(runnable);
                 mPushCount++;
                 mList.notifyAll();
             }
+            return true;
         }
 
         /**
@@ -343,11 +361,26 @@
             }
         }
 
-        private Runnable pop() throws InterruptedException {
+        /**
+         * Quit processing after the queue is cleared.
+         * All subsequent calls to push will fail.
+         * Note, this does not flush.
+         */
+        void quit() {
+            synchronized(mList) {
+                mQuitting = true;
+                mList.notifyAll();
+            }
+        }
+
+        // Returns the next runnable when available.
+        // Returns null iff the list is empty and quit has been called.
+        private @Nullable Runnable pop() throws InterruptedException {
             synchronized (mList) {
-                while (mList.isEmpty()) {
+                while (mList.isEmpty() && !mQuitting) {
                     mList.wait();
                 }
+                if (mList.isEmpty() && mQuitting) return null;
                 return mList.remove();
             }
         }
@@ -372,6 +405,7 @@
     public void detach() {
         mDelegate.detach();
         mNotifier.unregisterListener(this);
+        mCallbackThread.quit();
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
index 227424e..b817821 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
@@ -150,6 +150,8 @@
     @Override
     public void detach() {
         mUnderlying.detach();
+        // We should no longer have any pending calls
+        mTimer.quit();
     }
 
     private class Watchdog implements AutoCloseable {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java b/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
index bfcc7d8..fe91e66 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
@@ -18,9 +18,7 @@
 
 import android.annotation.NonNull;
 import android.os.Handler;
-import android.os.Looper;
-
-import java.util.concurrent.atomic.AtomicReference;
+import android.os.HandlerThread;
 
 /**
  * A simple timer, similar to java.util.Timer, but using the "uptime clock".
@@ -33,58 +31,45 @@
  * task.cancel();
  */
 class UptimeTimer {
-    private Handler mHandler = null;
+    private final Handler mHandler;
+    private final HandlerThread mHandlerThread;
 
     interface Task {
         void cancel();
     }
 
     UptimeTimer(String threadName) {
-        new Thread(this::threadFunc, threadName).start();
-        synchronized (this) {
-            while (mHandler == null) {
-                try {
-                    wait();
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        }
+        mHandlerThread = new HandlerThread(threadName);
+        mHandlerThread.start();
+        // Blocks until looper init
+        mHandler = new Handler(mHandlerThread.getLooper());
     }
 
+    // Note, this method is not internally synchronized.
+    // This is safe since Handlers are internally synchronized.
     Task createTask(@NonNull Runnable runnable, long uptimeMs) {
-        TaskImpl task = new TaskImpl(runnable);
-        mHandler.postDelayed(task, uptimeMs);
+        Object token = new Object();
+        TaskImpl task = new TaskImpl(mHandler, token);
+        mHandler.postDelayed(runnable, token, uptimeMs);
         return task;
     }
 
-    private void threadFunc() {
-        Looper.prepare();
-        synchronized (this) {
-            mHandler = new Handler(Looper.myLooper());
-            notifyAll();
-        }
-        Looper.loop();
+    void quit() {
+        mHandlerThread.quitSafely();
     }
 
-    private static class TaskImpl implements Task, Runnable {
-        private AtomicReference<Runnable> mRunnable = new AtomicReference<>();
+    private static class TaskImpl implements Task {
+        private final Handler mHandler;
+        private final Object mToken;
 
-        TaskImpl(@NonNull Runnable runnable) {
-            mRunnable.set(runnable);
+        public TaskImpl(Handler handler, Object token) {
+            mHandler = handler;
+            mToken = token;
         }
 
         @Override
         public void cancel() {
-            mRunnable.set(null);
+            mHandler.removeCallbacksAndMessages(mToken);
         }
-
-        @Override
-        public void run() {
-            Runnable runnable = mRunnable.get();
-            if (runnable != null) {
-                runnable.run();
-            }
-        }
-    }
+    };
 }
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
index 88e9fa5..1fb7cf5 100644
--- a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
@@ -18,19 +18,24 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.AlarmManager;
 import android.content.Context;
-import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationManagerInternal;
 import android.location.LocationRequest;
 import android.location.LocationTime;
 import android.os.Binder;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.TimestampedValue;
+import android.util.LocalLog;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
@@ -41,6 +46,7 @@
 import java.io.PrintWriter;
 import java.time.Duration;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * Monitors the GNSS time.
@@ -87,7 +93,7 @@
                 // Instead of polling GNSS time periodically, passive location updates are enabled.
                 // Once an update is received, the gnss time will be queried and suggested to
                 // TimeDetectorService.
-                mService.requestGnssTimeUpdates();
+                mService.startGnssListeningInternal();
             }
         }
     }
@@ -95,15 +101,28 @@
     private static final Duration GNSS_TIME_UPDATE_ALARM_INTERVAL = Duration.ofHours(4);
     private static final String ATTRIBUTION_TAG = "GnssTimeUpdateService";
 
+    /**
+     * A log that records the decisions to fetch a GNSS time update.
+     * This is logged in bug reports to assist with debugging issues with GNSS time suggestions.
+     */
+    private final LocalLog mLocalLog = new LocalLog(10, false /* useLocalTimestamps */);
+    /** The executor used for async operations */
+    private final Executor mExecutor = FgThread.getExecutor();
+    /** The handler used for async operations */
+    private final Handler mHandler = FgThread.getHandler();
+
     private final Context mContext;
     private final TimeDetectorInternal mTimeDetectorInternal;
     private final AlarmManager mAlarmManager;
     private final LocationManager mLocationManager;
     private final LocationManagerInternal mLocationManagerInternal;
 
-    @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
-    @Nullable private LocationListener mLocationListener;
-    @Nullable private TimestampedValue<Long> mLastSuggestedGnssTime;
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock") @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
+    @GuardedBy("mLock") @Nullable private LocationListener mLocationListener;
+
+    @Nullable private volatile TimestampedValue<Long> mLastSuggestedGnssTime;
 
     @VisibleForTesting
     GnssTimeUpdateService(@NonNull Context context, @NonNull AlarmManager alarmManager,
@@ -118,87 +137,133 @@
     }
 
     /**
-     * Request passive location updates. Such a request will not trigger any active locations or
-     * power usage itself.
+     * Used by {@link com.android.server.timedetector.GnssTimeUpdateServiceShellCommand} to force
+     * the service into GNSS listening mode.
+     */
+    @RequiresPermission(android.Manifest.permission.SET_TIME)
+    boolean startGnssListening() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.SET_TIME, "Start GNSS listening");
+        mLocalLog.log("startGnssListening() called");
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return startGnssListeningInternal();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
+     * Starts listening for passive location updates. Such a request will not trigger any active
+     * locations or power usage itself. Returns {@code true} if the service is listening after the
+     * method returns and {@code false} otherwise. At present this method only returns {@code false}
+     * if there is no GPS provider on the device.
+     *
+     * <p>If the service is already listening for locations this is a no-op. If the device is in a
+     * "sleeping" state between listening periods then it will return to listening.
      */
     @VisibleForTesting
-    void requestGnssTimeUpdates() {
-        if (D) {
-            Log.d(TAG, "requestGnssTimeUpdates()");
+    boolean startGnssListeningInternal() {
+        if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
+            logError("GPS provider does not exist on this device");
+            return false;
         }
 
-        if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
-            Log.e(TAG, "GPS provider does not exist on this device");
-            return;
+        synchronized (mLock) {
+            if (mLocationListener != null) {
+                logDebug("Already listening for GNSS updates");
+                return true;
+            }
+
+            // If startGnssListening() is called during manual tests to jump back into location
+            // listening then there will usually be an alarm set.
+            if (mAlarmListener != null) {
+                mAlarmManager.cancel(mAlarmListener);
+                mAlarmListener = null;
+            }
+
+            startGnssListeningLocked();
+            return true;
         }
+    }
+
+    @GuardedBy("mLock")
+    private void startGnssListeningLocked() {
+        logDebug("startGnssListeningLocked()");
 
         // Location Listener triggers onLocationChanged() when GNSS data is available, so
         // that the getGnssTimeMillis() function doesn't need to be continuously polled.
-        mLocationListener = new LocationListener() {
-            @Override
-            public void onLocationChanged(Location location) {
-                if (D) {
-                    Log.d(TAG, "onLocationChanged()");
-                }
-
-                // getGnssTimeMillis() can return null when the Master Location Switch for the
-                // foreground user is disabled.
-                LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
-                if (locationTime != null) {
-                    suggestGnssTime(locationTime);
-                } else {
-                    if (D) {
-                        Log.d(TAG, "getGnssTimeMillis() returned null");
-                    }
-                }
-
-                mLocationManager.removeUpdates(mLocationListener);
-                mLocationListener = null;
-
-                mAlarmListener = new AlarmManager.OnAlarmListener() {
-                    @Override
-                    public void onAlarm() {
-                        if (D) {
-                            Log.d(TAG, "onAlarm()");
-                        }
-                        mAlarmListener = null;
-                        requestGnssTimeUpdates();
-                    }
-                };
-
-                // Set next alarm to re-enable location updates.
-                long next = SystemClock.elapsedRealtime()
-                        + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
-                mAlarmManager.set(
-                        AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        next,
-                        TAG,
-                        mAlarmListener,
-                        FgThread.getHandler());
-            }
-        };
-
+        mLocationListener = location -> handleLocationAvailable();
         mLocationManager.requestLocationUpdates(
                 LocationManager.GPS_PROVIDER,
                 new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
                         .setMinUpdateIntervalMillis(0)
                         .build(),
-                FgThread.getExecutor(),
+                mExecutor,
                 mLocationListener);
     }
 
+    private void handleLocationAvailable() {
+        logDebug("handleLocationAvailable()");
+
+        // getGnssTimeMillis() can return null when the Master Location Switch for the
+        // foreground user is disabled.
+        LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
+        if (locationTime != null) {
+            String msg = "Passive location time received: " + locationTime;
+            logDebug(msg);
+            mLocalLog.log(msg);
+            suggestGnssTime(locationTime);
+        } else {
+            logDebug("getGnssTimeMillis() returned null");
+        }
+
+        synchronized (mLock) {
+            if (mLocationListener == null) {
+                logWarning("mLocationListener unexpectedly null");
+            } else {
+                mLocationManager.removeUpdates(mLocationListener);
+                mLocationListener = null;
+            }
+
+            if (mAlarmListener != null) {
+                logWarning("mAlarmListener was unexpectedly non-null");
+                mAlarmManager.cancel(mAlarmListener);
+            }
+
+            // Set next alarm to re-enable location updates.
+            long next = SystemClock.elapsedRealtime()
+                    + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
+            mAlarmListener = this::handleAlarmFired;
+            mAlarmManager.set(
+                    AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    next,
+                    TAG,
+                    mAlarmListener,
+                    mHandler);
+        }
+    }
+
+    private void handleAlarmFired() {
+        logDebug("handleAlarmFired()");
+
+        synchronized (mLock) {
+            mAlarmListener = null;
+            startGnssListeningLocked();
+        }
+    }
+
     /**
      * Convert LocationTime to TimestampedValue. Then suggest TimestampedValue to Time Detector.
      */
     private void suggestGnssTime(LocationTime locationTime) {
-        if (D) {
-            Log.d(TAG, "suggestGnssTime()");
-        }
+        logDebug("suggestGnssTime()");
+
         long gnssTime = locationTime.getTime();
         long elapsedRealtimeMs = locationTime.getElapsedRealtimeNanos() / 1_000_000L;
 
-        TimestampedValue<Long> timeSignal = new TimestampedValue<>(
-                elapsedRealtimeMs, gnssTime);
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(elapsedRealtimeMs, gnssTime);
         mLastSuggestedGnssTime = timeSignal;
 
         GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
@@ -209,11 +274,38 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
         pw.println("mLastSuggestedGnssTime: " + mLastSuggestedGnssTime);
-        pw.print("state: ");
-        if (mLocationListener != null) {
-            pw.println("time updates enabled");
-        } else {
-            pw.println("alarm enabled");
+        synchronized (mLock) {
+            pw.print("state: ");
+            if (mLocationListener != null) {
+                pw.println("time updates enabled");
+            } else {
+                pw.println("alarm enabled");
+            }
+        }
+        pw.println("Log:");
+        mLocalLog.dump(pw);
+    }
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+        new GnssTimeUpdateServiceShellCommand(this).exec(
+                this, in, out, err, args, callback, resultReceiver);
+    }
+
+    private void logError(String msg) {
+        Log.e(TAG, msg);
+        mLocalLog.log(msg);
+    }
+
+    private void logWarning(String msg) {
+        Log.w(TAG, msg);
+        mLocalLog.log(msg);
+    }
+
+    private void logDebug(String msg) {
+        if (D) {
+            Log.d(TAG, msg);
         }
     }
 }
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java
new file mode 100644
index 0000000..e757578
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/** Implements the shell command interface for {@link GnssTimeUpdateService}. */
+class GnssTimeUpdateServiceShellCommand extends ShellCommand {
+
+    /**
+     * The name of the service.
+     */
+    private static final String SHELL_COMMAND_SERVICE_NAME = "gnss_time_update_service";
+
+    /**
+     * A shell command that forces the service in to GNSS listening mode if it isn't already.
+     */
+    private static final String SHELL_COMMAND_START_GNSS_LISTENING = "start_gnss_listening";
+
+    @NonNull
+    private final GnssTimeUpdateService mGnssTimeUpdateService;
+
+    GnssTimeUpdateServiceShellCommand(GnssTimeUpdateService gnssTimeUpdateService) {
+        mGnssTimeUpdateService = Objects.requireNonNull(gnssTimeUpdateService);
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+
+        switch (cmd) {
+            case SHELL_COMMAND_START_GNSS_LISTENING:
+                return runStartGnssListening();
+            default: {
+                return handleDefaultCommands(cmd);
+            }
+        }
+    }
+
+    private int runStartGnssListening() {
+        boolean success = mGnssTimeUpdateService.startGnssListening();
+        getOutPrintWriter().println(success);
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.printf("Network Time Update Service (%s) commands:\n", SHELL_COMMAND_SERVICE_NAME);
+        pw.printf("  help\n");
+        pw.printf("    Print this help text.\n");
+        pw.printf("  %s\n", SHELL_COMMAND_START_GNSS_LISTENING);
+        pw.printf("    Forces the service in to GNSS listening mode (if it isn't already).\n");
+        pw.printf("    Prints true if the service is listening after this command.\n");
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index e00e029..e21feae 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1211,7 +1211,7 @@
             if (info.userId == userId
                     && info.agent.isTrusted()
                     && info.agent.shouldDisplayTrustGrantedMessage()
-                    && !TextUtils.isEmpty(info.agent.getMessage())) {
+                    && info.agent.getMessage() != null) {
                 trustGrantedMessages.add(info.agent.getMessage().toString());
             }
         }
diff --git a/services/core/java/com/android/server/utils/AlarmQueue.java b/services/core/java/com/android/server/utils/AlarmQueue.java
index 3f4def6..41373cd 100644
--- a/services/core/java/com/android/server/utils/AlarmQueue.java
+++ b/services/core/java/com/android/server/utils/AlarmQueue.java
@@ -34,6 +34,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.Comparator;
 import java.util.PriorityQueue;
 import java.util.function.Predicate;
 
@@ -52,6 +53,11 @@
     private static final boolean DEBUG = false;
 
     private static final long NOT_SCHEDULED = -1;
+    /**
+     * The threshold used to consider a new trigger time to be significantly different from the
+     * currently used trigger time.
+     */
+    private static final long SIGNIFICANT_TRIGGER_TIME_CHANGE_THRESHOLD_MS = MINUTE_IN_MILLIS;
 
     /**
      * Internal priority queue for each key's alarm, ordered by the time the alarm should go off.
@@ -59,7 +65,7 @@
      */
     private static class AlarmPriorityQueue<Q> extends PriorityQueue<Pair<Q, Long>> {
         AlarmPriorityQueue() {
-            super(1, (o1, o2) -> (int) (o1.second - o2.second));
+            super(1, Comparator.comparingLong(o -> o.second));
         }
 
         /**
@@ -306,8 +312,10 @@
         // earlier but not significantly so, then we essentially delay the check for some
         // apps by up to a minute.
         // 3. The alarm is after the current alarm.
+        final long timeShiftThresholdMs =
+                Math.min(SIGNIFICANT_TRIGGER_TIME_CHANGE_THRESHOLD_MS, mMinTimeBetweenAlarmsMs);
         if (mTriggerTimeElapsed == NOT_SCHEDULED
-                || nextTriggerTimeElapsed < mTriggerTimeElapsed - MINUTE_IN_MILLIS
+                || nextTriggerTimeElapsed < mTriggerTimeElapsed - timeShiftThresholdMs
                 || mTriggerTimeElapsed < nextTriggerTimeElapsed) {
             if (DEBUG) {
                 Slog.d(TAG, "Scheduling alarm at " + nextTriggerTimeElapsed
diff --git a/services/core/java/com/android/server/utils/Slogf.java b/services/core/java/com/android/server/utils/Slogf.java
index bbc5414..e88ac63 100644
--- a/services/core/java/com/android/server/utils/Slogf.java
+++ b/services/core/java/com/android/server/utils/Slogf.java
@@ -162,6 +162,21 @@
     }
 
     /**
+     * Logs a {@link Log.VEBOSE} message with an exception
+     *
+     * <p><strong>Note: </strong>the message will only be formatted if {@link Log#VERBOSE} logging
+     * is enabled for the given {@code tag}, but the compiler will still create an intermediate
+     * array of the objects for the {@code vargars}, which could affect garbage collection. So, if
+     * you're calling this method in a critical path, make sure to explicitly do the check before
+     * calling it.
+     */
+    public static void v(String tag, Exception exception, String format, @Nullable Object... args) {
+        if (!isLoggable(tag, Log.VERBOSE)) return;
+
+        v(tag, getMessage(format, args), exception);
+    }
+
+    /**
      * Logs a {@link Log.DEBUG} message.
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#DEBUG} logging is
@@ -177,6 +192,21 @@
     }
 
     /**
+     * Logs a {@link Log.DEBUG} message with an exception
+     *
+     * <p><strong>Note: </strong>the message will only be formatted if {@link Log#DEBUG} logging
+     * is enabled for the given {@code tag}, but the compiler will still create an intermediate
+     * array of the objects for the {@code vargars}, which could affect garbage collection. So, if
+     * you're calling this method in a critical path, make sure to explicitly do the check before
+     * calling it.
+     */
+    public static void d(String tag, Exception exception, String format, @Nullable Object... args) {
+        if (!isLoggable(tag, Log.DEBUG)) return;
+
+        d(tag, getMessage(format, args), exception);
+    }
+
+    /**
      * Logs a {@link Log.INFO} message.
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#INFO} logging is
@@ -192,6 +222,21 @@
     }
 
     /**
+     * Logs a {@link Log.INFO} message with an exception
+     *
+     * <p><strong>Note: </strong>the message will only be formatted if {@link Log#INFO} logging
+     * is enabled for the given {@code tag}, but the compiler will still create an intermediate
+     * array of the objects for the {@code vargars}, which could affect garbage collection. So, if
+     * you're calling this method in a critical path, make sure to explicitly do the check before
+     * calling it.
+     */
+    public static void i(String tag, Exception exception, String format, @Nullable Object... args) {
+        if (!isLoggable(tag, Log.INFO)) return;
+
+        i(tag, getMessage(format, args), exception);
+    }
+
+    /**
      * Logs a {@link Log.WARN} message.
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
@@ -220,6 +265,7 @@
 
         w(tag, getMessage(format, args), exception);
     }
+
     /**
      * Logs a {@link Log.ERROR} message.
      *
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index fcf0a90..6012993 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -224,8 +224,6 @@
 
     public void onSystemReady() {
         PowerManagerInternal pm = LocalServices.getService(PowerManagerInternal.class);
-        VirtualDeviceManagerInternal vdm = LocalServices.getService(
-                VirtualDeviceManagerInternal.class);
         AudioManager am = mContext.getSystemService(AudioManager.class);
         int ringerMode = am.getRingerModeInternal();
 
@@ -263,9 +261,11 @@
                     }
                 });
 
-        if (vdm != null){
-          vdm.registerVirtualDisplayListener(mVirtualDeviceListener);
-          vdm.registerAppsOnVirtualDeviceListener(mVirtualDeviceListener);
+        VirtualDeviceManagerInternal vdm = LocalServices.getService(
+                VirtualDeviceManagerInternal.class);
+        if (vdm != null) {
+            vdm.registerVirtualDisplayListener(mVirtualDeviceListener);
+            vdm.registerAppsOnVirtualDeviceListener(mVirtualDeviceListener);
         }
 
         registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
@@ -791,33 +791,35 @@
                 mAppsOnVirtualDevice.clear();
                 mAppsOnVirtualDevice.addAll(allRunningUids);
             }
-
-
         }
 
         /**
          * @param uid:       uid of the calling app.
          * @param displayId: the id of a Display.
          * @return Returns true if:
-         * 1) the displayId is valid, and it's owned by a virtual device
-         * 2) the displayId is invalid, and the calling app (uid) is running on a virtual device.
+         * <ul>
+         *   <li> the displayId is valid, and it's owned by a virtual device.</li>
+         *   <li> the displayId is invalid, and the calling app (uid) is running on a virtual
+         *        device.</li>
+         * </ul>
          */
         public boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                // The default display is the primary physical display on the phone.
+                return false;
+            }
+
             synchronized (mLock) {
-                switch (displayId) {
-                    case Display.DEFAULT_DISPLAY:
-                        // The default display is the primary physical display on the phone.
-                        return false;
-                    case Display.INVALID_DISPLAY:
-                        // There is no Display object associated with the Context of calling
-                        // {@link SystemVibratorManager}, checking the calling UID instead.
-                        return mAppsOnVirtualDevice.contains(uid);
-                    default:
-                        // Other valid display IDs representing valid logical displays will be
-                        // checked
-                        // against the active virtual displays set built with the registered
-                        // {@link VirtualDisplayListener}.
-                        return mVirtualDisplays.contains(displayId);
+                if (displayId == Display.INVALID_DISPLAY) {
+                    // There is no Display object associated with the Context of calling
+                    // {@link SystemVibratorManager}, checking the calling UID instead.
+                    return mAppsOnVirtualDevice.contains(uid);
+                } else {
+                    // Other valid display IDs representing valid logical displays will be
+                    // checked
+                    // against the active virtual displays set built with the registered
+                    // {@link VirtualDisplayListener}.
+                    return mVirtualDisplays.contains(displayId);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f25929c..d0b058b 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2713,6 +2713,13 @@
         checkPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT);
         synchronized (mLock) {
             WallpaperData data = mWallpaperMap.get(mCurrentUserId);
+            if (data == null) {
+                data = mWallpaperMap.get(UserHandle.USER_SYSTEM);
+                if (data == null) {
+                    Slog.e(TAG, "getWallpaperDimAmount: wallpaperData is null");
+                    return 0.0f;
+                }
+            }
             return data.mWallpaperDimAmount;
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index cceb58d..ffe24c0 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -87,7 +87,7 @@
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import com.android.server.pm.KnownPackages;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.vr.VrManagerInternal;
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index be80118..1c583be 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1522,8 +1522,17 @@
         this.task = newTask;
 
         if (shouldStartChangeTransition(newParent, oldParent)) {
-            // Animate change transition on TaskFragment level to get the correct window crop.
-            newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
+            if (mTransitionController.isShellTransitionsEnabled()) {
+                // For Shell transition, call #initializeChangeTransition directly to take the
+                // screenshot at the Activity level. And Shell will be in charge of handling the
+                // surface reparent and crop.
+                initializeChangeTransition(getBounds());
+            } else {
+                // For legacy app transition, we want to take a screenshot of the Activity surface,
+                // but animate the change transition on TaskFragment level to get the correct window
+                // crop.
+                newParent.initializeChangeTransition(getBounds(), getSurfaceControl());
+            }
         }
 
         super.onParentChanged(newParent, oldParent);
@@ -2120,7 +2129,7 @@
 
         mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
 
-        updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
+        updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
     }
 
     /**
@@ -7424,7 +7433,7 @@
         }
         final Rect frame = win.getRelativeFrame();
         final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
-                ? mAtmService.mUiContext.getDrawable(R.drawable.ic_account_circle)
+                ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
                 : mEnterpriseThumbnailDrawable;
         final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
                 .createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 037cd8e..d131457 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -387,6 +387,14 @@
                 callingUid, realCallingUid, UserHandle.USER_NULL);
         final SparseArray<String> startingUidPkgs = new SparseArray<>();
         final long origId = Binder.clearCallingIdentity();
+
+        SafeActivityOptions bottomOptions = null;
+        if (options != null) {
+            // To ensure the first N-1 activities (N == total # of activities) are also launched
+            // into the correct display, use a copy of the passed-in options (keeping only
+            // display-related info) for these activities.
+            bottomOptions = options.selectiveCloneDisplayOptions();
+        }
         try {
             intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
             final ActivityStarter[] starters = new ActivityStarter[intents.length];
@@ -435,7 +443,7 @@
                 final boolean top = i == intents.length - 1;
                 final SafeActivityOptions checkedOptions = top
                         ? options
-                        : null;
+                        : bottomOptions;
                 starters[i] = obtainStarter(intent, reason)
                         .setIntentGrants(intentGrants)
                         .setCaller(caller)
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bdbe787..8f5d838 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -345,7 +345,7 @@
      * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
      * change at runtime. Use mContext for non-UI purposes.
      */
-    final Context mUiContext;
+    private final Context mUiContext;
     final ActivityThread mSystemThread;
     H mH;
     UiHandler mUiHandler;
@@ -1040,6 +1040,10 @@
         }
     }
 
+    Context getUiContext() {
+        return mUiContext;
+    }
+
     UserManagerService getUserManager() {
         if (mUserManager == null) {
             IBinder b = ServiceManager.getService(Context.USER_SERVICE);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index dc91c15..28cd001 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -744,7 +744,7 @@
             // (e.g. AMS.startActivityAsUser).
             final long token = Binder.clearCallingIdentity();
             try {
-                return mService.getPackageManagerInternalLocked().resolveIntent(
+                return mService.getPackageManagerInternalLocked().resolveIntentExported(
                         intent, resolvedType, modifiedFlags, privateResolveFlags, userId, true,
                         filterCallingUid);
             } finally {
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index e0ac37a..01098de 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
 import static com.android.server.wm.ActivityRecord.INVALID_PID;
+import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
@@ -72,6 +73,33 @@
                         + ". Dropping notifyNoFocusedWindowAnr request");
                 return;
             }
+
+            // App is unresponsive, but we are actively trying to give focus to a window.
+            // Blame the window if possible since the window may not belong to the app.
+            DisplayContent display = mService.mRoot.getDisplayContent(activity.getDisplayId());
+            IBinder focusToken = display == null ? null : display.getInputMonitor().mInputFocus;
+            InputTarget focusTarget = mService.getInputTargetFromToken(focusToken);
+
+            if (focusTarget != null) {
+                // Check if we have a recent focus request, newer than the dispatch timeout, then
+                // ignore the focus request.
+                WindowState targetWindowState = focusTarget.getWindowState();
+                boolean requestIsValid = SystemClock.uptimeMillis()
+                        - display.getInputMonitor().mInputFocusRequestTimeMillis
+                        >= getInputDispatchingTimeoutMillisLocked(
+                                targetWindowState.getActivityRecord());
+
+                if (requestIsValid) {
+                    if (notifyWindowUnresponsive(focusToken, timeoutRecord)) {
+                        Slog.i(TAG_WM, "Blamed " + focusTarget.getWindowState().getName()
+                                + " using pending focus request. Focused activity: "
+                                + activity.getName());
+                        return;
+                    }
+                }
+            }
+
+
             Slog.i(TAG_WM, "ANR in " + activity.getName() + ".  Reason: " + timeoutRecord.mReason);
             dumpAnrStateLocked(activity, null /* windowState */, timeoutRecord.mReason);
             mUnresponsiveAppByDisplay.put(activity.getDisplayId(), activity);
@@ -208,6 +236,7 @@
             }
         }
         mService.mAmInternal.inputDispatchingResumed(unresponsiveApp.getPid());
+        mUnresponsiveAppByDisplay.remove(newFocus.getDisplayId());
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c940a65..d2c098b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -39,6 +39,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -746,7 +747,8 @@
         if (isKeyguardGoingAwayTransitOld(transit) && enter) {
             a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,
                     transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
-        } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
+        } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM) {
             a = null;
         } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {
             a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
@@ -1158,6 +1160,9 @@
             case TRANSIT_OLD_KEYGUARD_OCCLUDE: {
                 return "TRANSIT_OLD_KEYGUARD_OCCLUDE";
             }
+            case TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM: {
+                return "TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM";
+            }
             case TRANSIT_OLD_KEYGUARD_UNOCCLUDE: {
                 return "TRANSIT_OLD_KEYGUARD_UNOCCLUDE";
             }
@@ -1413,6 +1418,7 @@
 
     static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
         return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM
                 || transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
     }
 
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 4b0005d..7e62c61 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -34,6 +34,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -357,8 +358,14 @@
                 // When there is a closing app, the keyguard has already been occluded by an
                 // activity, and another activity has started on top of that activity, so normal
                 // app transition animation should be used.
-                return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
-                        : TRANSIT_OLD_ACTIVITY_OPEN;
+                if (!closingApps.isEmpty()) {
+                    return TRANSIT_OLD_ACTIVITY_OPEN;
+                }
+                if (!openingApps.isEmpty() && openingApps.valueAt(0).getActivityType()
+                        == ACTIVITY_TYPE_DREAM) {
+                    return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
+                }
+                return TRANSIT_OLD_KEYGUARD_OCCLUDE;
             case TRANSIT_KEYGUARD_UNOCCLUDE:
                 return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
         }
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d9ab971..a3f5401 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -36,6 +36,7 @@
 import android.view.SurfaceControl;
 import android.window.BackNavigationInfo;
 import android.window.OnBackInvokedCallbackInfo;
+import android.window.ScreenCapture;
 import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -422,7 +423,7 @@
             ComponentName activityComponent) {
         // Check if we have a screenshot of the previous activity, indexed by its
         // component name.
-        SurfaceControl.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots
+        ScreenCapture.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots
                 .get(activityComponent.flattenToString());
         return backBuffer != null ? backBuffer.getHardwareBuffer() : null;
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b10e420..2809307 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -231,6 +231,7 @@
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 import android.window.DisplayWindowPolicyController;
 import android.window.IDisplayAreaOrganizer;
+import android.window.ScreenCapture;
 import android.window.TransitionRequestInfo;
 
 import com.android.internal.R;
@@ -1152,6 +1153,7 @@
         mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
 
+        setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
     }
 
@@ -1618,24 +1620,6 @@
             }
             config = new Configuration();
             computeScreenConfiguration(config);
-        } else if (!(mTransitionController.isCollecting(this)
-                // If waiting for a remote display change, don't prematurely update configuration.
-                || mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange())) {
-            // No obvious action we need to take, but if our current state mismatches the
-            // activity manager's, update it, disregarding font scale, which should remain set
-            // to the value of the previous configuration.
-            // Here we're calling Configuration#unset() instead of setToDefaults() because we
-            // need to keep override configs clear of non-empty values (e.g. fontSize).
-            final Configuration currentConfig = getRequestedOverrideConfiguration();
-            mTmpConfiguration.unset();
-            mTmpConfiguration.updateFrom(currentConfig);
-            computeScreenConfiguration(mTmpConfiguration);
-            if (currentConfig.diff(mTmpConfiguration) != 0) {
-                mWaitingForConfig = true;
-                setLayoutNeeded();
-                mDisplayRotation.prepareNormalRotationAnimation();
-                config = new Configuration(mTmpConfiguration);
-            }
         }
 
         return config;
@@ -2685,16 +2669,6 @@
     }
 
     @Override
-    public void setWindowingMode(int windowingMode) {
-        // Intentionally call onRequestedOverrideConfigurationChanged() directly to change windowing
-        // mode and display windowing mode atomically.
-        mTmpConfiguration.setTo(getRequestedOverrideConfiguration());
-        mTmpConfiguration.windowConfiguration.setWindowingMode(windowingMode);
-        mTmpConfiguration.windowConfiguration.setDisplayWindowingMode(windowingMode);
-        onRequestedOverrideConfigurationChanged(mTmpConfiguration);
-    }
-
-    @Override
     void setDisplayWindowingMode(int windowingMode) {
         setWindowingMode(windowingMode);
     }
@@ -4261,7 +4235,7 @@
             return mImeTarget;
         }
 
-        private SurfaceControl createImeSurface(SurfaceControl.ScreenshotHardwareBuffer b,
+        private SurfaceControl createImeSurface(ScreenCapture.ScreenshotHardwareBuffer b,
                 Transaction t) {
             final HardwareBuffer buffer = b.getHardwareBuffer();
             ProtoLog.i(WM_DEBUG_IME, "create IME snapshot for %s, buff width=%s, height=%s",
@@ -4323,7 +4297,7 @@
                     || mImeSurface.getWidth() != dc.mInputMethodWindow.getFrame().width()
                     || mImeSurface.getHeight() != dc.mInputMethodWindow.getFrame().height();
             if (task != null && !task.isActivityTypeHomeOrRecents()) {
-                SurfaceControl.ScreenshotHardwareBuffer imeBuffer = renewImeSurface
+                ScreenCapture.ScreenshotHardwareBuffer imeBuffer = renewImeSurface
                         ? dc.mWmService.mTaskSnapshotController.snapshotImeFromAttachedTask(task)
                         : null;
                 if (imeBuffer != null) {
@@ -4932,12 +4906,12 @@
 
         // Send invalid rect and no width and height since it will screenshot the entire display.
         final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-        final SurfaceControl.DisplayCaptureArgs captureArgs =
-                new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+        final ScreenCapture.DisplayCaptureArgs captureArgs =
+                new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
                         .setUseIdentityTransform(inRotation)
                         .build();
-        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                SurfaceControl.captureDisplay(captureArgs);
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                ScreenCapture.captureDisplay(captureArgs);
         final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
         if (bitmap == null) {
             Slog.w(TAG_WM, "Failed to take screenshot");
diff --git a/services/core/java/com/android/server/wm/DisplayHashController.java b/services/core/java/com/android/server/wm/DisplayHashController.java
index 543d4ad..1a8b434 100644
--- a/services/core/java/com/android/server/wm/DisplayHashController.java
+++ b/services/core/java/com/android/server/wm/DisplayHashController.java
@@ -53,9 +53,9 @@
 import android.util.Size;
 import android.util.Slog;
 import android.view.MagnificationSpec;
-import android.view.SurfaceControl;
 import android.view.displayhash.DisplayHash;
 import android.view.displayhash.VerifiedDisplayHash;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -194,7 +194,7 @@
         return true;
     }
 
-    void generateDisplayHash(SurfaceControl.LayerCaptureArgs.Builder args,
+    void generateDisplayHash(ScreenCapture.LayerCaptureArgs.Builder args,
             Rect boundsInWindow, String hashAlgorithm, int uid, RemoteCallback callback) {
         if (!allowedToGenerateHash(uid)) {
             sendDisplayHashError(callback, DISPLAY_HASH_ERROR_TOO_MANY_REQUESTS);
@@ -217,8 +217,8 @@
 
         args.setGrayscale(displayHashParams.isGrayscaleBuffer());
 
-        SurfaceControl.ScreenshotHardwareBuffer screenshotHardwareBuffer =
-                SurfaceControl.captureLayers(args.build());
+        ScreenCapture.ScreenshotHardwareBuffer screenshotHardwareBuffer =
+                ScreenCapture.captureLayers(args.build());
         if (screenshotHardwareBuffer == null
                 || screenshotHardwareBuffer.getHardwareBuffer() == null) {
             Slog.w(TAG, "Failed to generate DisplayHash. Couldn't capture content");
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index cb59960..e780606 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -421,7 +421,7 @@
         mService = service;
         mContext = displayContent.isDefaultDisplay ? service.mContext
                 : service.mContext.createDisplayContext(displayContent.getDisplay());
-        mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
+        mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.getUiContext()
                 : service.mAtmService.mSystemThread
                         .getSystemUiContext(displayContent.getDisplayId());
         mDisplayContent = displayContent;
@@ -2183,9 +2183,7 @@
         }
         mDecorInsets.invalidate();
         mDecorInsets.mInfoForRotation[rotation].set(newInfo);
-        // If the device is booting, let the boot procedure trigger the new configuration.
-        // Otherwise the display configuration needs to be recomputed now.
-        return mService.mDisplayEnabled;
+        return true;
     }
 
     DecorInsets.Info getDecorInsetsInfo(int rotation, int w, int h) {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 9462d4f7..e0644b6 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -150,7 +150,10 @@
         final SettingsProvider.SettingsEntry overrideSettings =
                 mSettingsProvider.getOverrideSettings(displayInfo);
         overrideSettings.mWindowingMode = mode;
-        dc.setWindowingMode(mode);
+        final TaskDisplayArea defaultTda = dc.getDefaultTaskDisplayArea();
+        if (defaultTda != null) {
+            defaultTda.setWindowingMode(mode);
+        }
         mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
@@ -253,8 +256,10 @@
 
         // Setting windowing mode first, because it may override overscan values later.
         final int windowingMode = getWindowingModeLocked(settings, dc);
-        dc.setWindowingMode(windowingMode);
-
+        final TaskDisplayArea defaultTda = dc.getDefaultTaskDisplayArea();
+        if (defaultTda != null) {
+            defaultTda.setWindowingMode(windowingMode);
+        }
         final int userRotationMode = settings.mUserRotationMode != null
                 ? settings.mUserRotationMode : WindowManagerPolicy.USER_ROTATION_FREE;
         final int userRotation = settings.mUserRotation != null
@@ -311,10 +316,11 @@
      * changed.
      */
     boolean updateSettingsForDisplay(DisplayContent dc) {
-        if (dc.getWindowingMode() != getWindowingModeLocked(dc)) {
+        final TaskDisplayArea defaultTda = dc.getDefaultTaskDisplayArea();
+        if (defaultTda != null && defaultTda.getWindowingMode() != getWindowingModeLocked(dc)) {
             // For the time being the only thing that may change is windowing mode, so just update
             // that.
-            dc.setWindowingMode(getWindowingModeLocked(dc));
+            defaultTda.setWindowingMode(getWindowingModeLocked(dc));
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 3108d4e..2583514 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -101,7 +101,8 @@
             float thumbCenterX, float thumbCenterY, ClipData data) {
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
-                            Integer.toHexString(flags) + " data=" + data);
+                    Integer.toHexString(flags) + " data=" + data + " touch(" + touchX + ","
+                    + touchY + ") thumb center(" + thumbCenterX + "," + thumbCenterY + ")");
         }
 
         final IBinder dragToken = new Binder();
@@ -156,6 +157,7 @@
                     mDragState.mPid = callerPid;
                     mDragState.mUid = callerUid;
                     mDragState.mOriginalAlpha = alpha;
+                    mDragState.mAnimatedScale = callingWin.mGlobalScale;
                     mDragState.mToken = dragToken;
                     mDragState.mDisplayContent = displayContent;
                     mDragState.mData = data;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 2242bfd..25ff023 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -112,6 +112,7 @@
     int mTouchSource;
     boolean mDragResult;
     boolean mRelinquishDragSurfaceToDropTarget;
+    float mAnimatedScale = 1.0f;
     float mOriginalAlpha;
     float mOriginalX, mOriginalY;
     float mCurrentX, mCurrentY;
@@ -650,7 +651,8 @@
                 PropertyValuesHolder.ofFloat(
                         ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY,
                         mOriginalY - mThumbOffsetY),
-                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 1),
+                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale,
+                        mAnimatedScale),
                 PropertyValuesHolder.ofFloat(
                         ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2));
 
@@ -678,7 +680,7 @@
                         ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX),
                 PropertyValuesHolder.ofFloat(
                         ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY),
-                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 0),
+                PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, mAnimatedScale, 0),
                 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
         final AnimationListener listener = new AnimationListener();
         animator.setDuration(MIN_ANIMATION_DURATION_MS);
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 3e6e06a..14a1cd0 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -218,6 +218,12 @@
         if (dcTarget == null || mImeRequester == null) {
             return false;
         }
+        // Not ready to show if there is no IME control target.
+        final InsetsControlTarget controlTarget = mDisplayContent.getImeTarget(IME_TARGET_CONTROL);
+        if (controlTarget == null) {
+            return false;
+        }
+
         ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeRequester: %s",
                 dcTarget.getWindow().getName(), mImeRequester.getWindow() == null
                         ? mImeRequester : mImeRequester.getWindow().getName());
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 610ce35..7860b15 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -52,6 +52,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.InputConfig;
+import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -77,7 +78,8 @@
     private final WindowManagerService mService;
 
     // Current input focus token for keys and other non-touch events.  May be null.
-    private IBinder mInputFocus = null;
+    IBinder mInputFocus = null;
+    long mInputFocusRequestTimeMillis = 0;
 
     // When true, need to call updateInputWindowsLw().
     private boolean mUpdateInputWindowsNeeded = true;
@@ -479,6 +481,7 @@
         }
 
         mInputFocus = focusToken;
+        mInputFocusRequestTimeMillis = SystemClock.uptimeMillis();
         mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
         EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
                 "reason=UpdateInputWindows");
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 317c93e..ea82417 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -481,7 +481,7 @@
     }
 
     private void updateRoundedCorners(WindowState mainWindow) {
-        final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
+        final SurfaceControl windowSurface = mainWindow.getSurfaceControl();
         if (windowSurface != null && windowSurface.isValid()) {
             final Transaction transaction = mActivityRecord.getSyncTransaction();
 
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 1fd66fc..d497d8c 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -141,15 +141,16 @@
             return false;
 
         } else {
-            mResultActivities.add(r);
             if (r.resultTo != null) {
                 // If this activity is sending a reply to a previous activity, we can't do
                 // anything with it now until we reach the start of the reply chain.
                 // NOTE: that we are assuming the result is always to the previous activity,
                 // which is almost always the case but we really shouldn't count on.
+                mResultActivities.add(r);
                 return false;
             } else if (mTargetTaskFound && allowTaskReparenting && mTargetTask.affinity != null
                     && mTargetTask.affinity.equals(r.taskAffinity)) {
+                mResultActivities.add(r);
                 // This activity has an affinity for our task. Either remove it if we are
                 // clearing or move it over to our task. Note that we currently punt on the case
                 // where we are resetting a task that is not at the top but who has activities
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index d92a1f4..a638784 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -118,6 +118,34 @@
     }
 
     /**
+     * To ensure that two activities, one using this object, and the other using the
+     * SafeActivityOptions returned from this function, are launched into the same display through
+     * ActivityStartController#startActivities, all display-related information, i.e.
+     * displayAreaToken, launchDisplayId and callerDisplayId, are cloned.
+     */
+    @Nullable SafeActivityOptions selectiveCloneDisplayOptions() {
+        final ActivityOptions options = cloneLaunchingDisplayOptions(mOriginalOptions);
+        final ActivityOptions callerOptions = cloneLaunchingDisplayOptions(mCallerOptions);
+        if (options == null && callerOptions == null) {
+            return null;
+        }
+
+        final SafeActivityOptions safeOptions = new SafeActivityOptions(options,
+                mOriginalCallingPid, mOriginalCallingUid);
+        safeOptions.mCallerOptions = callerOptions;
+        safeOptions.mRealCallingPid = mRealCallingPid;
+        safeOptions.mRealCallingUid = mRealCallingUid;
+        return safeOptions;
+    }
+
+    private ActivityOptions cloneLaunchingDisplayOptions(ActivityOptions options) {
+        return options == null ? null : ActivityOptions.makeBasic()
+                .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
+                .setLaunchDisplayId(options.getLaunchDisplayId())
+                .setCallerDisplayId((options.getCallerDisplayId()));
+    }
+
+    /**
      * Overrides options with options from a caller and records {@link Binder#getCallingPid}/
      * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this
      * method.
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index fd8b614..24d4e98 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -52,6 +52,7 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
+import android.window.ScreenCapture;
 
 import com.android.internal.R;
 import com.android.internal.protolog.common.ProtoLog;
@@ -167,7 +168,7 @@
         final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
 
         try {
-            final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer;
+            final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer;
             if (isSizeChanged) {
                 final DisplayAddress address = displayInfo.address;
                 if (!(address instanceof DisplayAddress.Physical)) {
@@ -186,22 +187,22 @@
                 // the whole display to include the rounded corner overlays.
                 setSkipScreenshotForRoundedCornerOverlays(false, t);
                 mRoundedCornerOverlay = displayContent.findRoundedCornerOverlays();
-                final SurfaceControl.DisplayCaptureArgs captureArgs =
-                        new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+                final ScreenCapture.DisplayCaptureArgs captureArgs =
+                        new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
                                 .setSourceCrop(new Rect(0, 0, width, height))
                                 .setAllowProtected(true)
                                 .setCaptureSecureLayers(true)
                                 .build();
-                screenshotBuffer = SurfaceControl.captureDisplay(captureArgs);
+                screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
             } else {
-                SurfaceControl.LayerCaptureArgs captureArgs =
-                        new SurfaceControl.LayerCaptureArgs.Builder(
+                ScreenCapture.LayerCaptureArgs captureArgs =
+                        new ScreenCapture.LayerCaptureArgs.Builder(
                                 displayContent.getSurfaceControl())
                                 .setCaptureSecureLayers(true)
                                 .setAllowProtected(true)
                                 .setSourceCrop(new Rect(0, 0, width, height))
                                 .build();
-                screenshotBuffer = SurfaceControl.captureLayers(captureArgs);
+                screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
             }
 
             if (screenshotBuffer == null) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index fb68fe6..b9739f03 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -324,7 +324,7 @@
         final int callingPid = Binder.getCallingPid();
         // Validate and resolve ClipDescription data before clearing the calling identity
         validateAndResolveDragMimeTypeExtras(data, callingUid, callingPid, mPackageName);
-        validateDragFlags(flags, callingUid);
+        validateDragFlags(flags);
         final long ident = Binder.clearCallingIdentity();
         try {
             return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
@@ -349,11 +349,7 @@
      * Validates the given drag flags.
      */
     @VisibleForTesting
-    void validateDragFlags(int flags, int callingUid) {
-        if (callingUid == Process.SYSTEM_UID) {
-            throw new IllegalStateException("Need to validate before calling identify is cleared");
-        }
-
+    void validateDragFlags(int flags) {
         if ((flags & View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION) != 0) {
             if (!mCanStartTasksFromRecents) {
                 throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
@@ -367,9 +363,6 @@
     @VisibleForTesting
     void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
             String callingPackage) {
-        if (callingUid == Process.SYSTEM_UID) {
-            throw new IllegalStateException("Need to validate before calling identify is cleared");
-        }
         final ClipDescription desc = data != null ? data.getDescription() : null;
         if (desc == null) {
             return;
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index f3670e4..94d4dde 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -45,6 +45,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.animation.Animation;
 import android.view.animation.Transformation;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -433,16 +434,16 @@
     private void doCreateExtensionSurface(SurfaceControl leash, Rect edgeBounds,
             Rect extensionRect, int xPos, int yPos, String layerName,
             Transaction startTransaction) {
-        SurfaceControl.LayerCaptureArgs captureArgs =
-                new SurfaceControl.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
+        ScreenCapture.LayerCaptureArgs captureArgs =
+                new ScreenCapture.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
                         .setSourceCrop(edgeBounds)
                         .setFrameScale(1)
                         .setPixelFormat(PixelFormat.RGBA_8888)
                         .setChildrenOnly(true)
                         .setAllowProtected(true)
                         .build();
-        final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer =
-                SurfaceControl.captureLayers(captureArgs);
+        final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
+                ScreenCapture.captureLayers(captureArgs);
 
         if (edgeBuffer == null) {
             // The leash we are trying to screenshot may have been removed by this point, which is
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index a7ef36b..0c36d27 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -28,6 +28,7 @@
 import android.hardware.HardwareBuffer;
 import android.util.Slog;
 import android.view.SurfaceControl;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
@@ -89,7 +90,7 @@
 
         freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget();
         if (freezeTarget != null) {
-            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
+            ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
                     freezeTarget, startBounds);
             final HardwareBuffer buffer = screenshotBuffer == null ? null
                     : screenshotBuffer.getHardwareBuffer();
@@ -183,31 +184,31 @@
         return mLeash != null;
     }
 
-    private static SurfaceControl.ScreenshotHardwareBuffer createSnapshotBuffer(
+    private static ScreenCapture.ScreenshotHardwareBuffer createSnapshotBuffer(
             @NonNull SurfaceControl target, @Nullable Rect bounds) {
         Rect cropBounds = null;
         if (bounds != null) {
             cropBounds = new Rect(bounds);
             cropBounds.offsetTo(0, 0);
         }
-        SurfaceControl.LayerCaptureArgs captureArgs =
-                new SurfaceControl.LayerCaptureArgs.Builder(target)
+        ScreenCapture.LayerCaptureArgs captureArgs =
+                new ScreenCapture.LayerCaptureArgs.Builder(target)
                         .setSourceCrop(cropBounds)
                         .setCaptureSecureLayers(true)
                         .setAllowProtected(true)
                         .build();
-        return SurfaceControl.captureLayers(captureArgs);
+        return ScreenCapture.captureLayers(captureArgs);
     }
 
     @VisibleForTesting
-    SurfaceControl.ScreenshotHardwareBuffer createSnapshotBufferInner(
+    ScreenCapture.ScreenshotHardwareBuffer createSnapshotBufferInner(
             SurfaceControl target, Rect bounds) {
         return createSnapshotBuffer(target, bounds);
     }
 
     @VisibleForTesting
     GraphicBuffer createFromHardwareBufferInner(
-            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
+            ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer) {
         return GraphicBuffer.createFromHardwareBuffer(screenshotBuffer.getHardwareBuffer());
     }
 
@@ -220,7 +221,7 @@
          * @param screenshotBuffer A thumbnail or placeholder for thumbnail to initialize with.
          */
         Snapshot(SurfaceControl.Transaction t,
-                SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
+                ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
             GraphicBuffer graphicBuffer = createFromHardwareBufferInner(screenshotBuffer);
 
             mSurfaceControl = mAnimatable.makeAnimationLeash()
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a9d5c69..728102e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4459,6 +4459,14 @@
             // transferring the transform on the leash to the task, reset this state once we're
             // moving out of pip
             setCanAffectSystemUiFlags(true);
+            // Turn on userLeaveHint so other app can enter PiP mode.
+            mTaskSupervisor.mUserLeaving = true;
+            // Allow entering PiP from current top most activity when we are leaving PiP.
+            final Task topFocused = mRootWindowContainer.getTopDisplayFocusedRootTask();
+            if (topFocused != null) {
+                final ActivityRecord ar = topFocused.getTopResumedActivity();
+                enableEnterPipOnTaskSwitch(ar, null /* toFrontTask */, ar, null /* opts */);
+            }
             mRootWindowContainer.notifyActivityPipModeChanged(this, null);
         }
         if (likelyResolvedMode == WINDOWING_MODE_PINNED) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 4063cae4..b6c14bb 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -172,6 +172,8 @@
      */
     private final boolean mCanHostHomeTask;
 
+    private final Configuration mTempConfiguration = new Configuration();
+
     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
                     int displayAreaFeature) {
         this(displayContent, service, name, displayAreaFeature, false /* createdByOrganizer */,
@@ -1893,6 +1895,15 @@
     }
 
     @Override
+    public void setWindowingMode(int windowingMode) {
+        mTempConfiguration.setTo(getRequestedOverrideConfiguration());
+        WindowConfiguration tempRequestWindowConfiguration = mTempConfiguration.windowConfiguration;
+        tempRequestWindowConfiguration.setWindowingMode(windowingMode);
+        tempRequestWindowConfiguration.setDisplayWindowingMode(windowingMode);
+        onRequestedOverrideConfigurationChanged(mTempConfiguration);
+    }
+
+    @Override
     TaskDisplayArea getTaskDisplayArea() {
         return this;
     }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 1f6690ac..de4c84c 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -89,6 +89,7 @@
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.window.ITaskFragmentOrganizer;
+import android.window.ScreenCapture;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOrganizerToken;
 
@@ -97,7 +98,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.am.HostingRecord;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -306,7 +307,7 @@
 
     //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
     // implemented
-    HashMap<String, SurfaceControl.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
+    HashMap<String, ScreenCapture.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
 
     private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
             new EnsureActivitiesVisibleHelper(this);
@@ -1595,12 +1596,14 @@
         boolean pauseImmediately = false;
         boolean shouldAutoPip = false;
         if (resuming != null) {
+            // We do not want to trigger auto-PiP upon launch of a translucent activity.
+            final boolean resumingOccludesParent = resuming.occludesParent();
             // Resuming the new resume activity only if the previous activity can't go into Pip
             // since we want to give Pip activities a chance to enter Pip before resuming the
             // next activity.
             final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
                     "shouldAutoPipWhilePausing", userLeaving);
-            if (userLeaving && lastResumedCanPip
+            if (userLeaving && resumingOccludesParent && lastResumedCanPip
                     && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
                 shouldAutoPip = true;
             } else if (!lastResumedCanPip) {
@@ -1859,7 +1862,7 @@
                 ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
                         r.mActivityComponent.flattenToString());
                 Rect outBounds = r.getBounds();
-                SurfaceControl.ScreenshotHardwareBuffer backBuffer = SurfaceControl.captureLayers(
+                ScreenCapture.ScreenshotHardwareBuffer backBuffer = ScreenCapture.captureLayers(
                         r.mSurfaceControl,
                         new Rect(0, 0, outBounds.width(), outBounds.height()),
                         1f);
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 1362094..8444489 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -135,7 +135,7 @@
         final DisplayContent display = suggestedDisplayArea.mDisplayContent;
         if (DEBUG) {
             appendLog("display-id=" + display.getDisplayId()
-                    + " display-windowing-mode=" + display.getWindowingMode()
+                    + " task-display-area-windowing-mode=" + suggestedDisplayArea.getWindowingMode()
                     + " suggested-display-area=" + suggestedDisplayArea);
         }
 
@@ -154,7 +154,7 @@
         // source is a freeform window in a fullscreen display launching an activity on the same
         // display.
         if (launchMode == WINDOWING_MODE_UNDEFINED
-                && canInheritWindowingModeFromSource(display, source)) {
+                && canInheritWindowingModeFromSource(display, suggestedDisplayArea, source)) {
             // The source's windowing mode may be different from its task, e.g. activity is set
             // to fullscreen and its task is pinned windowing mode when the activity is entering
             // pip.
@@ -182,7 +182,8 @@
         // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
         // different, we should recalculating the bounds.
         boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow = false;
-        final boolean canApplyFreeformPolicy = canApplyFreeformWindowPolicy(display, launchMode);
+        final boolean canApplyFreeformPolicy =
+                canApplyFreeformWindowPolicy(suggestedDisplayArea, launchMode);
         if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
                 && (canApplyFreeformPolicy || canApplyPipWindowPolicy(launchMode))) {
             hasInitialBounds = true;
@@ -237,7 +238,8 @@
                         == display.getDisplayId())) {
             // Only set windowing mode if display is in freeform. If the display is in fullscreen
             // mode we should only launch a task in fullscreen mode.
-            if (currentParams.hasWindowingMode() && display.inFreeformWindowingMode()) {
+            if (currentParams.hasWindowingMode()
+                    && suggestedDisplayArea.inFreeformWindowingMode()) {
                 launchMode = currentParams.mWindowingMode;
                 fullyResolvedCurrentParam = launchMode != WINDOWING_MODE_FREEFORM;
                 if (DEBUG) {
@@ -265,11 +267,11 @@
         // this step is to define the default policy when there is no initial bounds or a fully
         // resolved current params from callers.
 
-        // hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay is set if the outParams.mBounds
+        // hasInitialBoundsForSuggestedDisplayAreaInFreeformMode is set if the outParams.mBounds
         // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
         // different, we should recalcuating the bounds.
-        boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = false;
-        if (display.inFreeformWindowingMode()) {
+        boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = false;
+        if (suggestedDisplayArea.inFreeformWindowingMode()) {
             if (launchMode == WINDOWING_MODE_PINNED) {
                 if (DEBUG) appendLog("picture-in-picture");
             } else if (!root.isResizeable()) {
@@ -278,7 +280,7 @@
                     if (outParams.mBounds.isEmpty()) {
                         getTaskBounds(root, suggestedDisplayArea, layout, launchMode,
                                 hasInitialBounds, outParams.mBounds);
-                        hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay = true;
+                        hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = true;
                     }
                     if (DEBUG) appendLog("unresizable-freeform");
                 } else {
@@ -288,10 +290,10 @@
                 }
             }
         } else {
-            if (DEBUG) appendLog("non-freeform-display");
+            if (DEBUG) appendLog("non-freeform-task-display-area");
         }
         // If launch mode matches display windowing mode, let it inherit from display.
-        outParams.mWindowingMode = launchMode == display.getWindowingMode()
+        outParams.mWindowingMode = launchMode == suggestedDisplayArea.getWindowingMode()
                 ? WINDOWING_MODE_UNDEFINED : launchMode;
 
         if (phase == PHASE_WINDOWING_MODE) {
@@ -301,7 +303,7 @@
         // STEP 3: Finalize the display area. Here we allow WM shell route all launches that match
         // certain criteria to specific task display areas.
         final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode
-                : display.getWindowingMode();
+                : suggestedDisplayArea.getWindowingMode();
         TaskDisplayArea taskDisplayArea = suggestedDisplayArea;
         // If launch task display area is set in options we should just use it. We assume the
         // suggestedDisplayArea has the right one in this case.
@@ -319,14 +321,17 @@
                 mTmpDisplayArea = displayArea;
                 return true;
             });
-            // We may need to recalculate the bounds if the new TaskDisplayArea is different from
-            // the suggested one we used to calculate the bounds.
+            // We may need to recalculate the bounds and the windowing mode if the new
+            // TaskDisplayArea is different from the suggested one we used to calculate the two
+            // configurations.
             if (mTmpDisplayArea != null && mTmpDisplayArea != suggestedDisplayArea) {
+                outParams.mWindowingMode = (launchMode == mTmpDisplayArea.getWindowingMode())
+                        ? WINDOWING_MODE_UNDEFINED : launchMode;
                 if (hasInitialBoundsForSuggestedDisplayAreaInFreeformWindow) {
                     outParams.mBounds.setEmpty();
                     getLayoutBounds(mTmpDisplayArea, root, layout, outParams.mBounds);
                     hasInitialBounds = !outParams.mBounds.isEmpty();
-                } else if (hasInitialBoundsForSuggestedDisplayAreaInFreeformDisplay) {
+                } else if (hasInitialBoundsForSuggestedDisplayAreaInFreeformMode) {
                     outParams.mBounds.setEmpty();
                     getTaskBounds(root, mTmpDisplayArea, layout, launchMode,
                             hasInitialBounds, outParams.mBounds);
@@ -533,7 +538,7 @@
     }
 
     private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
-            @Nullable ActivityRecord source) {
+            TaskDisplayArea suggestedDisplayArea, @Nullable ActivityRecord source) {
         if (source == null) {
             return false;
         }
@@ -541,7 +546,7 @@
         // There is not really any strong reason to tie the launching windowing mode and the source
         // on freeform displays. The launching windowing mode is more tied to the content of the new
         // activities.
-        if (display.inFreeformWindowingMode()) {
+        if (suggestedDisplayArea.inFreeformWindowingMode()) {
             return false;
         }
 
@@ -557,9 +562,11 @@
         return display.getDisplayId() == source.getDisplayId();
     }
 
-    private boolean canApplyFreeformWindowPolicy(@NonNull DisplayContent display, int launchMode) {
+    private boolean canApplyFreeformWindowPolicy(@NonNull TaskDisplayArea suggestedDisplayArea,
+            int launchMode) {
         return mSupervisor.mService.mSupportsFreeformWindowManagement
-                && (display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM);
+                && (suggestedDisplayArea.inFreeformWindowingMode()
+                || launchMode == WINDOWING_MODE_FREEFORM);
     }
 
     private boolean canApplyPipWindowPolicy(int launchMode) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 534616f..9306749 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -58,6 +58,7 @@
 import android.view.WindowInsets.Type;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager.LayoutParams;
+import android.window.ScreenCapture;
 import android.window.TaskSnapshot;
 
 import com.android.internal.R;
@@ -389,11 +390,11 @@
     }
 
     @Nullable
-    SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
+    ScreenCapture.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
             TaskSnapshot.Builder builder) {
         Point taskSize = new Point();
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "createTaskSnapshot");
-        final SurfaceControl.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
+        final ScreenCapture.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
                 mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize, builder);
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         builder.setTaskSize(taskSize);
@@ -401,7 +402,7 @@
     }
 
     @Nullable
-    private SurfaceControl.ScreenshotHardwareBuffer createImeSnapshot(@NonNull Task task,
+    private ScreenCapture.ScreenshotHardwareBuffer createImeSnapshot(@NonNull Task task,
             int pixelFormat) {
         if (task.getSurfaceControl() == null) {
             if (DEBUG_SCREENSHOT) {
@@ -410,11 +411,11 @@
             return null;
         }
         final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
-        SurfaceControl.ScreenshotHardwareBuffer imeBuffer = null;
+        ScreenCapture.ScreenshotHardwareBuffer imeBuffer = null;
         if (imeWindow != null && imeWindow.isWinVisibleLw()) {
             final Rect bounds = imeWindow.getParentFrame();
             bounds.offsetTo(0, 0);
-            imeBuffer = SurfaceControl.captureLayersExcluding(imeWindow.getSurfaceControl(),
+            imeBuffer = ScreenCapture.captureLayersExcluding(imeWindow.getSurfaceControl(),
                     bounds, 1.0f, pixelFormat, null);
         }
         return imeBuffer;
@@ -425,7 +426,7 @@
      * task to keep IME visibility while app transitioning.
      */
     @Nullable
-    SurfaceControl.ScreenshotHardwareBuffer snapshotImeFromAttachedTask(@NonNull Task task) {
+    ScreenCapture.ScreenshotHardwareBuffer snapshotImeFromAttachedTask(@NonNull Task task) {
         // Check if the IME targets task ready to take the corresponding IME snapshot, if not,
         // means the task is not yet visible for some reasons and no need to snapshot IME surface.
         if (checkIfReadyToSnapshot(task) == null) {
@@ -438,7 +439,7 @@
     }
 
     @Nullable
-    SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
+    ScreenCapture.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
             float scaleFraction, int pixelFormat, Point outTaskSize, TaskSnapshot.Builder builder) {
         if (task.getSurfaceControl() == null) {
             if (DEBUG_SCREENSHOT) {
@@ -473,8 +474,8 @@
         }
         builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isVisible());
 
-        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                SurfaceControl.captureLayersExcluding(
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                ScreenCapture.captureLayersExcluding(
                         task.getSurfaceControl(), mTmpRect, scaleFraction,
                         pixelFormat, excludeLayers);
         if (outTaskSize != null) {
@@ -508,7 +509,7 @@
             return null;
         }
 
-        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
                 createTaskSnapshot(task, builder);
 
         if (screenshotBuffer == null) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 16fe4da..723aa19 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -40,8 +40,9 @@
 import static android.view.WindowManager.TransitionType;
 import static android.view.WindowManager.transitTypeToString;
 import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+import static android.window.TransitionInfo.FLAG_FILLS_TASK;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
-import static android.window.TransitionInfo.FLAG_IS_EMBEDDED;
 import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
 import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -77,6 +78,7 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.RemoteTransition;
+import android.window.ScreenCapture;
 import android.window.TransitionInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -569,17 +571,16 @@
                 t.setLayer(targetLeash, target.getLastLayer());
                 target.getRelativePosition(tmpPos);
                 t.setPosition(targetLeash, tmpPos.x, tmpPos.y);
-                final Rect clipRect;
                 // No need to clip the display in case seeing the clipped content when during the
                 // display rotation. No need to clip activities because they rely on clipping on
                 // task layers.
                 if (target.asDisplayContent() != null || target.asActivityRecord() != null) {
-                    clipRect = null;
+                    t.setCrop(targetLeash, null /* crop */);
                 } else {
-                    clipRect = target.getRequestedOverrideBounds();
-                    clipRect.offset(-tmpPos.x, -tmpPos.y);
+                    // Crop to the requested bounds.
+                    final Rect clipRect = target.getRequestedOverrideBounds();
+                    t.setWindowCrop(targetLeash, clipRect.width(), clipRect.height());
                 }
-                t.setCrop(targetLeash, clipRect);
                 t.setCornerRadius(targetLeash, 0);
                 t.setShadowRadius(targetLeash, 0);
                 t.setMatrix(targetLeash, 1, 0, 0, 1);
@@ -1839,8 +1840,10 @@
                     flags |= FLAG_WILL_IME_SHOWN;
                 }
             }
+            Task parentTask = null;
             final ActivityRecord record = wc.asActivityRecord();
             if (record != null) {
+                parentTask = record.getTask();
                 if (record.mUseTransferredAnimation) {
                     flags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
                 }
@@ -1848,6 +1851,26 @@
                     flags |= FLAG_IS_VOICE_INTERACTION;
                 }
             }
+            final TaskFragment taskFragment = wc.asTaskFragment();
+            if (taskFragment != null && task == null) {
+                parentTask = taskFragment.getTask();
+            }
+            if (parentTask != null) {
+                if (parentTask.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
+                    // Whether this is in a Task with embedded activity.
+                    flags |= FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
+                }
+                final Rect taskBounds = parentTask.getBounds();
+                final Rect startBounds = mAbsoluteBounds;
+                final Rect endBounds = wc.getBounds();
+                if (taskBounds.width() == startBounds.width()
+                        && taskBounds.height() == startBounds.height()
+                        && taskBounds.width() == endBounds.width()
+                        && taskBounds.height() == endBounds.height()) {
+                    // Whether the container fills the Task bounds before and after the transition.
+                    flags |= FLAG_FILLS_TASK;
+                }
+            }
             final DisplayContent dc = wc.asDisplayContent();
             if (dc != null) {
                 flags |= FLAG_IS_DISPLAY;
@@ -1864,9 +1887,6 @@
             if (occludesKeyguard(wc)) {
                 flags |= FLAG_OCCLUDES_KEYGUARD;
             }
-            if (wc.isEmbedded()) {
-                flags |= FLAG_IS_EMBEDDED;
-            }
             return flags;
         }
     }
@@ -2106,14 +2126,14 @@
 
             Rect cropBounds = new Rect(bounds);
             cropBounds.offsetTo(0, 0);
-            SurfaceControl.LayerCaptureArgs captureArgs =
-                    new SurfaceControl.LayerCaptureArgs.Builder(wc.getSurfaceControl())
+            ScreenCapture.LayerCaptureArgs captureArgs =
+                    new ScreenCapture.LayerCaptureArgs.Builder(wc.getSurfaceControl())
                             .setSourceCrop(cropBounds)
                             .setCaptureSecureLayers(true)
                             .setAllowProtected(true)
                             .build();
-            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                    SurfaceControl.captureLayers(captureArgs);
+            ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                    ScreenCapture.captureLayers(captureArgs);
             final HardwareBuffer buffer = screenshotBuffer == null ? null
                     : screenshotBuffer.getHardwareBuffer();
             if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
@@ -2121,8 +2141,12 @@
                 Slog.w(TAG, "Failed to capture screenshot for " + wc);
                 return false;
             }
+            final boolean isDisplayRotation = wc.asDisplayContent() != null
+                    && wc.asDisplayContent().isRotationChanging();
+            // Some tests may check the name "RotationLayer" to detect display rotation.
+            final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
             SurfaceControl snapshotSurface = wc.makeAnimationLeash()
-                    .setName("transition snapshot: " + wc.toString())
+                    .setName(name)
                     .setOpaque(true)
                     .setParent(wc.getSurfaceControl())
                     .setSecure(screenshotBuffer.containsSecureLayers())
@@ -2132,9 +2156,8 @@
             mFrozen.add(wc);
             final ChangeInfo changeInfo = Objects.requireNonNull(mChanges.get(wc));
             changeInfo.mSnapshot = snapshotSurface;
-            if (wc.asDisplayContent() != null) {
-                // This isn't cheap, so only do it for rotations: assume display-level is rotate
-                // since most of the time it is.
+            if (isDisplayRotation) {
+                // This isn't cheap, so only do it for display rotations.
                 changeInfo.mSnapshotLuma = RotationAnimationUtils.getMedianBorderLuma(
                         screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
             }
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 221e186..77d0f37 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -67,7 +67,7 @@
 
     /** Which sync method to use for transition syncs. */
     static final int SYNC_METHOD =
-            android.os.SystemProperties.getBoolean("persist.wm.debug.shell_transit_blast", true)
+            android.os.SystemProperties.getBoolean("persist.wm.debug.shell_transit_blast", false)
                     ? BLASTSyncEngine.METHOD_BLAST : BLASTSyncEngine.METHOD_NONE;
 
     /** The same as legacy APP_TRANSITION_TIMEOUT_MS. */
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d652b8e..0fd3e9b 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -53,6 +53,7 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.animation.Animation;
+import android.window.ScreenCapture;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLogImpl;
@@ -931,7 +932,7 @@
         final Rect bounds = wallpaperWindowState.getBounds();
         bounds.offsetTo(0, 0);
 
-        SurfaceControl.ScreenshotHardwareBuffer wallpaperBuffer = SurfaceControl.captureLayers(
+        ScreenCapture.ScreenshotHardwareBuffer wallpaperBuffer = ScreenCapture.captureLayers(
                 wallpaperWindowState.getSurfaceControl(), bounds, 1 /* frameScale */);
 
         if (wallpaperBuffer == null) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index bc66852..8cc0d5d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -622,7 +622,7 @@
         setInitialSurfaceControlProperties(makeSurface());
     }
 
-    void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
+    void setInitialSurfaceControlProperties(Builder b) {
         setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
         if (showSurfaceOnCreation()) {
             getSyncTransaction().show(mSurfaceControl);
@@ -652,7 +652,7 @@
         mLastSurfacePosition.set(0, 0);
         mLastDeltaRotation = Surface.ROTATION_0;
 
-        final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null)
+        final Builder b = mWmService.makeSurfaceBuilder(null)
                 .setContainerLayer()
                 .setName(getName());
 
@@ -2437,7 +2437,7 @@
         } while (current != null);
     }
 
-    SurfaceControl.Builder makeSurface() {
+    Builder makeSurface() {
         final WindowContainer p = getParent();
         return p.makeChildSurface(this);
     }
@@ -2446,7 +2446,7 @@
      * @param child The WindowContainer this child surface is for, or null if the Surface
      *              is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
      */
-    SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+    Builder makeChildSurface(WindowContainer child) {
         final WindowContainer p = getParent();
         // Give the parent a chance to set properties. In hierarchy v1 we rely
         // on this to set full-screen dimensions on all our Surface-less Layers.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5ad6fbd..88c47db 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -289,6 +289,7 @@
 import android.view.displayhash.VerifiedDisplayHash;
 import android.window.ClientWindowFrames;
 import android.window.ITaskFpsCallback;
+import android.window.ScreenCapture;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
 
@@ -3980,7 +3981,7 @@
      * Generates and returns an up-to-date {@link Bitmap} for the specified taskId.
      *
      * @param taskId                  The task ID of the task for which a Bitmap is requested.
-     * @param layerCaptureArgsBuilder A {@link SurfaceControl.LayerCaptureArgs.Builder} with
+     * @param layerCaptureArgsBuilder A {@link ScreenCapture.LayerCaptureArgs.Builder} with
      *                                arguments for how to capture the Bitmap. The caller can
      *                                specify any arguments, but this method will ensure that the
      *                                specified task's SurfaceControl is used and the crop is set to
@@ -3990,7 +3991,7 @@
      */
     @Nullable
     public Bitmap captureTaskBitmap(int taskId,
-            @NonNull SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder) {
+            @NonNull ScreenCapture.LayerCaptureArgs.Builder layerCaptureArgsBuilder) {
         if (mTaskSnapshotController.shouldDisableSnapshots()) {
             return null;
         }
@@ -4009,7 +4010,7 @@
             mTmpRect.offsetTo(0, 0);
 
             final SurfaceControl sc = task.getSurfaceControl();
-            final SurfaceControl.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
+            final ScreenCapture.ScreenshotHardwareBuffer buffer = ScreenCapture.captureLayers(
                     layerCaptureArgsBuilder.setLayer(sc).setSourceCrop(mTmpRect).build());
             if (buffer == null) {
                 Slog.w(TAG, "Could not get screenshot buffer for taskId: " + taskId);
@@ -5810,6 +5811,21 @@
         return -1;
     }
 
+    /**
+     * Return the display Id that has the given uniqueId. Unique ID is defined in
+     * {@link DisplayInfo#uniqueId}.
+     */
+    @Override
+    public int getDisplayIdByUniqueId(String uniqueId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(uniqueId);
+            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
+                return displayContent.mDisplayId;
+            }
+        }
+        return -1;
+    }
+
     @Override
     public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
         if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
@@ -9085,8 +9101,8 @@
         // be covering it with the same uid. We want to make sure we include content that's
         // covering to ensure we get as close as possible to what the user sees
         final int uid = session.mUid;
-        SurfaceControl.LayerCaptureArgs.Builder args =
-                new SurfaceControl.LayerCaptureArgs.Builder(displaySurfaceControl)
+        ScreenCapture.LayerCaptureArgs.Builder args =
+                new ScreenCapture.LayerCaptureArgs.Builder(displaySurfaceControl)
                         .setUid(uid)
                         .setSourceCrop(boundsInDisplay);
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index c22091b..2838304 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -264,8 +264,23 @@
 
     private int runDisplayDensity(PrintWriter pw) throws RemoteException {
         String densityStr = getNextArg();
+        String option = getNextOption();
+        String arg = getNextArg();
         int density;
-        final int displayId = getDisplayId(densityStr);
+        int displayId = Display.DEFAULT_DISPLAY;
+        if ("-d".equals(option) && arg != null) {
+            try {
+                displayId = Integer.parseInt(arg);
+            } catch (NumberFormatException e) {
+                getErrPrintWriter().println("Error: bad number " + e);
+            }
+        } else if ("-u".equals(option) && arg != null) {
+            displayId = mInterface.getDisplayIdByUniqueId(arg);
+            if (displayId == Display.INVALID_DISPLAY) {
+                getErrPrintWriter().println("Error: the uniqueId is invalid ");
+                return -1;
+            }
+        }
 
         if (densityStr == null) {
             printInitialDisplayDensity(pw, displayId);
@@ -1312,7 +1327,7 @@
         pw.println("  size [reset|WxH|WdpxHdp] [-d DISPLAY_ID]");
         pw.println("    Return or override display size.");
         pw.println("    width and height in pixels unless suffixed with 'dp'.");
-        pw.println("  density [reset|DENSITY] [-d DISPLAY_ID]");
+        pw.println("  density [reset|DENSITY] [-d DISPLAY_ID] [-u UNIQUE_ID]");
         pw.println("    Return or override display density.");
         pw.println("  folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]");
         pw.println("    Return or override folded area.");
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 72e7e65..8055590 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
@@ -631,12 +630,6 @@
             getResolvedOverrideConfiguration().updateFrom(
                     mFixedRotationTransformState.mRotatedOverrideConfiguration);
         }
-        if (getTaskDisplayArea() == null) {
-            // We only defined behaviors of system windows in fullscreen mode, i.e. windows not
-            // contained in a task display area.
-            getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
-                    WINDOWING_MODE_FULLSCREEN);
-        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
index 261dda7..b93b8d8 100644
--- a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -30,6 +30,7 @@
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.window.ScreenCapture;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -118,8 +119,8 @@
         Point size = new Point();
         display.getSize(size);
         Rect crop = new Rect(0, 0, size.x, size.y);
-        SurfaceControl.ScreenshotHardwareBuffer buffer =
-                SurfaceControl.captureLayers(surfaceControl, crop, 1);
+        ScreenCapture.ScreenshotHardwareBuffer buffer =
+                ScreenCapture.captureLayers(surfaceControl, crop, 1);
         if (buffer == null) {
             return 0;
         }
diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
index 8197b67..daca153 100644
--- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp
+++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp
@@ -21,6 +21,7 @@
 #include <android/keycodes.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <input/Input.h>
 #include <linux/uinput.h>
 #include <math.h>
 #include <nativehelper/JNIHelp.h>
@@ -271,6 +272,14 @@
                 ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
                 return -errno;
             }
+            uinput_abs_setup slotAbsSetup;
+            slotAbsSetup.code = ABS_MT_SLOT;
+            slotAbsSetup.absinfo.maximum = MAX_POINTERS;
+            slotAbsSetup.absinfo.minimum = 0;
+            if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
+                ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
+                return -errno;
+            }
         }
         if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
             ALOGE("Error creating uinput device: %s", strerror(errno));
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 891bc0f..78b4ce2 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -2090,6 +2090,14 @@
     return static_cast<jint>(ret.value_or(BATTERY_STATUS_UNKNOWN));
 }
 
+static jstring nativeGetBatteryDevicePath(JNIEnv* env, jobject nativeImplObj, jint deviceId) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+
+    const std::optional<std::string> batteryPath =
+            im->getInputManager()->getReader().getBatteryDevicePath(deviceId);
+    return batteryPath ? env->NewStringUTF(batteryPath->c_str()) : nullptr;
+}
+
 static void nativeReloadKeyboardLayouts(JNIEnv* env, jobject nativeImplObj) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
 
@@ -2371,6 +2379,7 @@
         {"setLightColor", "(III)V", (void*)nativeSetLightColor},
         {"getBatteryCapacity", "(I)I", (void*)nativeGetBatteryCapacity},
         {"getBatteryStatus", "(I)I", (void*)nativeGetBatteryStatus},
+        {"getBatteryDevicePath", "(I)Ljava/lang/String;", (void*)nativeGetBatteryDevicePath},
         {"reloadKeyboardLayouts", "()V", (void*)nativeReloadKeyboardLayouts},
         {"reloadDeviceAliases", "()V", (void*)nativeReloadDeviceAliases},
         {"dump", "()Ljava/lang/String;", (void*)nativeDump},
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 6b05d8f..267cff6 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -97,6 +97,16 @@
                     <xs:annotation name="nonnull"/>
                     <xs:annotation name="final"/>
                 </xs:element>
+                <!-- Set of thresholds that dictate the change needed for screen brightness
+                adaptations while in idle mode -->
+                <xs:element type="thresholds" name="displayBrightnessChangeThresholdsIdle" minOccurs="0" maxOccurs="1">
+                    <xs:annotation name="final"/>
+                </xs:element>
+                <!-- Set of thresholds that dictate the change needed for ambient brightness
+                adaptations while in idle mode -->
+                <xs:element type="thresholds" name="ambientBrightnessChangeThresholdsIdle" minOccurs="0" maxOccurs="1">
+                    <xs:annotation name="final"/>
+                </xs:element>
             </xs:sequence>
         </xs:complexType>
     </xs:element>
@@ -319,13 +329,13 @@
     <!-- Thresholds for brightness changes. -->
     <xs:complexType name="thresholds">
         <xs:sequence>
-            <!-- Brightening thresholds. -->
+            <!-- Brightening thresholds for active screen brightness mode. -->
             <xs:element name="brighteningThresholds" type="brightnessThresholds" minOccurs="0"
                         maxOccurs="1" >
                 <xs:annotation name="nonnull"/>
                 <xs:annotation name="final"/>
             </xs:element>
-            <!-- Darkening thresholds. -->
+            <!-- Darkening thresholds for active screen brightness mode. -->
             <xs:element name="darkeningThresholds" type="brightnessThresholds" minOccurs="0"
                         maxOccurs="1" >
                 <xs:annotation name="nonnull"/>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index fb7a920..f8bff75 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -61,11 +61,13 @@
   public class DisplayConfiguration {
     ctor public DisplayConfiguration();
     method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds();
+    method public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholdsIdle();
     method public final java.math.BigInteger getAmbientLightHorizonLong();
     method public final java.math.BigInteger getAmbientLightHorizonShort();
     method public com.android.server.display.config.AutoBrightness getAutoBrightness();
     method @Nullable public final com.android.server.display.config.DensityMapping getDensityMapping();
     method @NonNull public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholds();
+    method public final com.android.server.display.config.Thresholds getDisplayBrightnessChangeThresholdsIdle();
     method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
     method public final com.android.server.display.config.SensorDetails getLightSensor();
     method public final com.android.server.display.config.SensorDetails getProxSensor();
@@ -80,11 +82,13 @@
     method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
     method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();
     method public final void setAmbientBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
+    method public final void setAmbientBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
     method public final void setAmbientLightHorizonLong(java.math.BigInteger);
     method public final void setAmbientLightHorizonShort(java.math.BigInteger);
     method public void setAutoBrightness(com.android.server.display.config.AutoBrightness);
     method public final void setDensityMapping(@Nullable com.android.server.display.config.DensityMapping);
     method public final void setDisplayBrightnessChangeThresholds(@NonNull com.android.server.display.config.Thresholds);
+    method public final void setDisplayBrightnessChangeThresholdsIdle(com.android.server.display.config.Thresholds);
     method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
     method public final void setLightSensor(com.android.server.display.config.SensorDetails);
     method public final void setProxSensor(com.android.server.display.config.SensorDetails);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 333895e..bb6bd4a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -375,7 +375,7 @@
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
 import com.android.server.pm.UserRestrictionsUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -8336,9 +8336,8 @@
                 + PackageManager.FEATURE_DEVICE_ADMIN + " feature.");
     }
 
-    // TODO(b/240562946): Remove owner name from API parameters.
     @Override
-    public boolean setDeviceOwner(ComponentName admin, String ownerName, int userId,
+    public boolean setDeviceOwner(ComponentName admin, int userId,
             boolean setProfileOwnerOnCurrentUserIfNecessary) {
         if (!mHasFeature) {
             logMissingFeatureAction("Cannot set " + ComponentName.flattenToShortString(admin)
@@ -8794,9 +8793,8 @@
         });
     }
 
-    // TODO(b/240562946): Remove owner name from API parameters.
     @Override
-    public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
+    public boolean setProfileOwner(ComponentName who, int userHandle) {
         if (!mHasFeature) {
             logMissingFeatureAction("Cannot set " + ComponentName.flattenToShortString(who)
                     + " as profile owner for user " + userHandle);
@@ -10222,6 +10220,11 @@
                     ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo(
                             enabledPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES,
                             userIdToCheck);
+
+                    if (applicationInfo == null) {
+                        return false;
+                    }
+
                     systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
                 } catch (RemoteException e) {
                     Slogf.i(LOG_TAG, "Can't talk to package managed", e);
@@ -10817,9 +10820,7 @@
 
         // Set admin.
         setActiveAdmin(profileOwner, /* refreshing= */ true, userId);
-        final String ownerName = getProfileOwnerNameUnchecked(
-                Process.myUserHandle().getIdentifier());
-        setProfileOwner(profileOwner, ownerName, userId);
+        setProfileOwner(profileOwner, userId);
 
         synchronized (getLockObject()) {
             DevicePolicyData policyData = getUserData(userId);
@@ -15412,24 +15413,7 @@
                 }
             }
 
-            final String[] feature_allow =
-                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
-            final String[] feature_disallow =
-                    { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
-
-            boolean compatible = true;
-            for (Account account : accounts) {
-                if (hasAccountFeatures(am, account, feature_disallow)) {
-                    Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]);
-                    compatible = false;
-                    break;
-                }
-                if (!hasAccountFeatures(am, account, feature_allow)) {
-                    Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]);
-                    compatible = false;
-                    break;
-                }
-            }
+            boolean compatible = !hasIncompatibleAccounts(am, accounts);
             if (compatible) {
                 Slogf.w(LOG_TAG, "All accounts are compatible");
             } else {
@@ -15439,6 +15423,27 @@
         });
     }
 
+    private boolean hasIncompatibleAccounts(AccountManager am, Account[] accounts) {
+        // TODO(b/244284408): Add test
+        final String[] feature_allow =
+                { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED };
+        final String[] feature_disallow =
+                { DevicePolicyManager.ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED };
+
+        for (Account account : accounts) {
+            if (hasAccountFeatures(am, account, feature_disallow)) {
+                Slogf.e(LOG_TAG, "%s has %s", account, feature_disallow[0]);
+                return true;
+            }
+            if (!hasAccountFeatures(am, account, feature_allow)) {
+                Slogf.e(LOG_TAG, "%s doesn't have %s", account, feature_allow[0]);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     private boolean hasAccountFeatures(AccountManager am, Account account, String[] features) {
         try {
             return am.hasFeatures(account, features, null, null).getResult();
@@ -17658,8 +17663,7 @@
             maybeInstallDevicePolicyManagementRoleHolderInUser(userInfo.id);
 
             installExistingAdminPackage(userInfo.id, admin.getPackageName());
-            if (!enableAdminAndSetProfileOwner(
-                    userInfo.id, caller.getUserId(), admin, provisioningParams.getOwnerName())) {
+            if (!enableAdminAndSetProfileOwner(userInfo.id, caller.getUserId(), admin)) {
                 throw new ServiceSpecificException(
                         ERROR_SETTING_PROFILE_OWNER_FAILED,
                         "Error setting profile owner.");
@@ -17848,10 +17852,9 @@
     }
 
     private boolean enableAdminAndSetProfileOwner(
-            @UserIdInt int userId, @UserIdInt int callingUserId, ComponentName adminComponent,
-            String ownerName) {
+            @UserIdInt int userId, @UserIdInt int callingUserId, ComponentName adminComponent) {
         enableAndSetActiveAdmin(userId, callingUserId, adminComponent);
-        return setProfileOwner(adminComponent, ownerName, userId);
+        return setProfileOwner(adminComponent, userId);
     }
 
     private void enableAndSetActiveAdmin(
@@ -18048,11 +18051,9 @@
             }
 
 
-            if (!setActiveAdminAndDeviceOwner(
-                    deviceOwnerUserId, deviceAdmin, provisioningParams.getOwnerName())) {
+            if (!setActiveAdminAndDeviceOwner(deviceOwnerUserId, deviceAdmin)) {
                 throw new ServiceSpecificException(
-                        ERROR_SET_DEVICE_OWNER_FAILED,
-                        "Failed to set device owner.");
+                        ERROR_SET_DEVICE_OWNER_FAILED, "Failed to set device owner.");
             }
 
             disallowAddUser();
@@ -18179,12 +18180,12 @@
     }
 
     private boolean setActiveAdminAndDeviceOwner(
-            @UserIdInt int userId, ComponentName adminComponent, String name) {
+            @UserIdInt int userId, ComponentName adminComponent) {
         enableAndSetActiveAdmin(userId, userId, adminComponent);
         // TODO(b/178187130): Directly set DO and remove the check once silent provisioning is no
         //  longer used.
         if (getDeviceOwnerComponent(/* callingUserOnly= */ true) == null) {
-            return setDeviceOwner(adminComponent, name, userId,
+            return setDeviceOwner(adminComponent, userId,
                     /* setProfileOwnerOnCurrentUserIfNecessary= */ true);
         }
         return true;
@@ -18706,7 +18707,10 @@
         }
         AccountManager am = AccountManager.get(mContext);
         Account[] accounts = am.getAccounts();
-        return accounts.length == 0;
+        if (accounts.length == 0) {
+            return true;
+        }
+        return !hasIncompatibleAccounts(am, accounts);
     }
 
     private void setBypassDevicePolicyManagementRoleQualificationStateInternal(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 1fa2f53..4343225 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -50,6 +50,7 @@
 
     private final DevicePolicyManagerService mService;
     private int mUserId = UserHandle.USER_SYSTEM;
+    //TODO(b/240562946): remove mName once it is not used by setDeviceOwner
     private String mName = "";
     private ComponentName mComponent;
     private boolean mSetDoOnly;
@@ -256,7 +257,7 @@
         mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId);
 
         try {
-            if (!mService.setDeviceOwner(mComponent, mName, mUserId,
+            if (!mService.setDeviceOwner(mComponent, mUserId,
                     /* setProfileOwnerOnCurrentUserIfNecessary= */ !mSetDoOnly)) {
                 throw new RuntimeException(
                         "Can't set package " + mComponent + " as device owner.");
@@ -287,7 +288,7 @@
         mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId);
 
         try {
-            if (!mService.setProfileOwner(mComponent, mName, mUserId)) {
+            if (!mService.setProfileOwner(mComponent, mUserId)) {
                 throw new RuntimeException("Can't set component "
                         + mComponent.flattenToShortString() + " as profile owner for user "
                         + mUserId);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index dbed091..f921ccf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -929,6 +929,9 @@
             startCoreServices(t);
             startOtherServices(t);
             startApexServices(t);
+            // Only update the timeout after starting all the services so that we use
+            // the default timeout to start system server.
+            updateWatchdogTimeout(t);
         } catch (Throwable ex) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting system services", ex);
@@ -1499,10 +1502,6 @@
             SQLiteCompatibilityWalFlags.reset();
             t.traceEnd();
 
-            t.traceBegin("UpdateWatchdogTimeout");
-            Watchdog.getInstance().registerSettingsObserver(context);
-            t.traceEnd();
-
             // Records errors and logs, for example wtf()
             // Currently this service indirectly depends on SettingsProvider so do this after
             // InstallSystemProviders.
@@ -3055,6 +3054,12 @@
         t.traceEnd(); // startApexServices
     }
 
+    private void updateWatchdogTimeout(@NonNull TimingsTraceAndSlog t) {
+        t.traceBegin("UpdateWatchdogTimeout");
+        Watchdog.getInstance().registerSettingsObserver(mSystemContext);
+        t.traceEnd();
+    }
+
     private boolean deviceHasConfigString(@NonNull Context context, @StringRes int resId) {
         String serviceName = context.getString(resId);
         return !TextUtils.isEmpty(serviceName);
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 3c68662..f05b1d4 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -218,6 +218,9 @@
             BackgroundThread.get().getThreadHandler().post(
                     () -> {
                         try {
+                            if (sSelfService.mIProfcollect == null) {
+                                return;
+                            }
                             sSelfService.mIProfcollect.process();
                         } catch (RemoteException e) {
                             Log.e(LOG_TAG, "Failed to process profiles in background: "
diff --git a/services/proguard.flags b/services/proguard.flags
index 606f360..27fe505 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -127,3 +127,7 @@
 -keep,allowoptimization,allowaccessmodification class com.android.server.usage.StorageStatsManagerLocal { *; }
 -keep,allowoptimization,allowaccessmodification class com.android.internal.util.** { *; }
 -keep,allowoptimization,allowaccessmodification class android.os.** { *; }
+
+# CoverageService guards optional jacoco class references with a runtime guard, so we can safely
+# suppress build-time warnings.
+-dontwarn org.jacoco.agent.rt.*
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index df1d244..3ef8586a 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -60,9 +60,9 @@
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowUserManager;
 import com.android.server.wm.ActivityTaskManagerInternal;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 9c0f713..f3ac7d5 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -21,14 +21,25 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivity
 import android.os.Binder
 import android.os.UserHandle
 import android.util.ArrayMap
-import com.android.server.pm.*
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.AppsFilterImpl
+import com.android.server.pm.PackageManagerService
+import com.android.server.pm.PackageManagerServiceInjector
+import com.android.server.pm.PackageManagerServiceTestParams
+import com.android.server.pm.PackageManagerTracedLock
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.PendingPackageBroadcasts
+import com.android.server.pm.Settings
+import com.android.server.pm.SharedLibrariesImpl
+import com.android.server.pm.UserManagerInternal
+import com.android.server.pm.UserManagerService
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.parsing.pkg.ParsedPackage
+import com.android.server.pm.pkg.AndroidPackage
+import com.android.server.pm.pkg.component.ParsedActivity
 import com.android.server.pm.resolution.ComponentResolver
 import com.android.server.pm.snapshot.PackageDataSnapshot
 import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType
@@ -168,7 +179,7 @@
     lateinit var params: Params
 
     private lateinit var mockPendingBroadcasts: PendingPackageBroadcasts
-    private lateinit var mockPkg: AndroidPackage
+    private lateinit var mockPkg: AndroidPackageInternal
     private lateinit var mockPkgSetting: PackageSetting
     private lateinit var service: PackageManagerService
 
@@ -287,7 +298,7 @@
                     .apply(block)
                     .hideAsFinal()
 
-    private fun makePkgSetting(pkgName: String, pkg: AndroidPackage) =
+    private fun makePkgSetting(pkgName: String, pkg: AndroidPackageInternal) =
         PackageSetting(
             pkgName, null, File("/test"),
             null, null, null, null, 0, 0, 0, 0, null, null, null, null, null,
@@ -297,7 +308,7 @@
                 this.flags = this.flags or ApplicationInfo.FLAG_SYSTEM
             }
             this.pkgState.isUpdatedSystemApp = params.isUpdatedSystemApp
-            this.pkg = pkg
+            setPkg(pkg)
         }
 
     private fun makeTestData() {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 391dd36..5361041 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -31,8 +31,8 @@
 import android.util.SparseArray
 import android.util.SparseIntArray
 import com.android.internal.R
-import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.component.ParsedActivityImpl
 import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
 import com.android.server.pm.pkg.component.ParsedAttributionImpl
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index 652dc38..766ab94 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -18,14 +18,15 @@
 
 import android.content.Intent
 import android.content.pm.ApplicationInfo
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import android.os.Build
 import android.os.PatternMatcher
 import android.util.ArraySet
 import com.android.server.SystemConfig
 import com.android.server.compat.PlatformCompat
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationCollector
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
@@ -87,7 +88,7 @@
 
     @Test
     fun verifyV1NoValidIntentFilter() {
-        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+        val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { TEST_PKG_NAME }
             whenever(targetSdkVersion) { Build.VERSION_CODES.R }
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index c9601de..e4d124e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -29,7 +29,8 @@
 import android.util.SparseArray
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.pm.Computer
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
 import com.android.server.pm.pkg.component.ParsedActivityImpl
@@ -303,7 +304,7 @@
             )
         }
 
-        fun mockPkg(packageName: String) = mockThrowOnUnmocked<AndroidPackage> {
+        fun mockPkg(packageName: String) = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(this.packageName) { packageName }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index 7273b0b..c22bb53 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -29,7 +29,8 @@
 import android.os.Process
 import android.util.ArraySet
 import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
 import com.android.server.pm.pkg.component.ParsedActivityImpl
@@ -520,7 +521,7 @@
         pkgUserState1: PackageStateInternal.() -> PackageUserStateInternal = {
             PackageUserStateInternal.DEFAULT }
     ) = mockThrowOnUnmocked<PackageStateInternal> {
-        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+        val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { pkgName }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index ed60c50..e55ff3b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -37,7 +37,8 @@
 import android.util.SparseArray
 import android.util.Xml
 import com.android.server.pm.Computer
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
 import com.android.server.pm.pkg.component.ParsedActivityImpl
@@ -1046,7 +1047,7 @@
         otherDomains: List<String> = listOf(),
         isSystemApp: Boolean = false
     ) = mockThrowOnUnmocked<PackageStateInternal> {
-        val pkg = mockThrowOnUnmocked<AndroidPackage> {
+        val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { pkgName }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
index 0a54094..b985c04 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationProxyTest.kt
@@ -29,7 +29,7 @@
 import android.os.UserHandle
 import android.util.ArraySet
 import com.android.server.DeviceIdleInternal
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.verify.domain.DomainVerificationCollector
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index fc20c26..427b5b3 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -19,16 +19,16 @@
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.PackageUserStateInternal
 import android.content.pm.verify.domain.DomainVerificationState
 import android.os.Build
 import android.os.Process
 import android.util.ArraySet
 import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
 import com.android.server.pm.pkg.PackageStateInternal
+import com.android.server.pm.pkg.PackageUserStateInternal
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
@@ -187,7 +187,7 @@
         }
 
 
-        fun mockPkg() = mockThrowOnUnmocked<AndroidPackage> {
+        fun mockPkg() = mockThrowOnUnmocked<AndroidPackageInternal> {
             whenever(packageName) { TEST_PKG }
             whenever(targetSdkVersion) { Build.VERSION_CODES.S }
             whenever(isEnabled) { true }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 589633c..6bb5f39 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -18,8 +18,6 @@
 
 import android.content.Intent
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import android.content.pm.verify.domain.DomainVerificationManager
 import android.content.pm.verify.domain.DomainVerificationState
 import android.content.pm.verify.domain.DomainVerificationUserState
@@ -28,9 +26,12 @@
 import android.os.Process
 import android.util.ArraySet
 import android.util.SparseArray
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.AndroidPackageInternal
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
@@ -107,7 +108,7 @@
 
     fun mockPkgState(pkgName: String, domainSetId: UUID) =
         mockThrowOnUnmocked<PackageStateInternal> {
-            val pkg = mockThrowOnUnmocked<AndroidPackage> {
+            val pkg = mockThrowOnUnmocked<AndroidPackageInternal> {
                 whenever(packageName) { pkgName }
                 whenever(targetSdkVersion) { Build.VERSION_CODES.S }
                 whenever(isEnabled) { true }
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
index d68b517..353341e 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
@@ -42,6 +42,7 @@
 import android.widget.TextView;
 
 import androidx.test.espresso.NoActivityResumedException;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.infra.AndroidFuture;
@@ -80,6 +81,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 245615459)
     public void launch_targetActivityFinishesSuccessfully_futureCompletedWithSameResults() {
         AndroidFuture<GameSessionActivityResult> resultFuture =
                 startTestActivityViaGameSessionTrampolineActivity();
@@ -96,6 +98,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 245616660)
     public void launch_trampolineActivityProcessDeath_futureCompletedWithSameResults() {
         setAlwaysFinishActivities(true);
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index f9a60b6..d9c622d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -167,9 +167,9 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.tare.EconomyManagerInternal;
 import com.android.server.usage.AppStandbyInternal;
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 82334f2..c0688d1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -15,10 +15,8 @@
  */
 package com.android.server.appop;
 
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_ERRORED;
-import static android.app.AppOpsManager.MODE_FOREGROUND;
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_READ_SMS;
@@ -41,7 +39,6 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 
-import android.app.ActivityManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
 import android.content.ContentResolver;
@@ -58,7 +55,7 @@
 
 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 
 import org.junit.After;
@@ -335,124 +332,6 @@
         assertThat(getLoggedOps()).isNull();
     }
 
-    private void setupProcStateTests() {
-        // For the location proc state tests
-        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_FOREGROUND);
-        mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0;
-        mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0;
-        mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0;
-    }
-
-    @Test
-    public void testUidProcStateChange_cachedToTopToCached() throws Exception {
-        setupProcStateTests();
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
-                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        // Second time to make sure that settle time is overcome
-        Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-    }
-
-    @Test
-    public void testUidProcStateChange_cachedToFgs() {
-        setupProcStateTests();
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-    }
-
-    @Test
-    public void testUidProcStateChange_cachedToFgsLocation() {
-        setupProcStateTests();
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
-    }
-
-    @Test
-    public void testUidProcStateChange_topToFgs() throws Exception {
-        setupProcStateTests();
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
-                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        // Second time to make sure that settle time is overcome
-        Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-    }
-
-    @Test
-    public void testUidProcStateChange_topToFgsLocationToFgs() throws Exception {
-        setupProcStateTests();
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
-                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        // Second time to make sure that settle time is overcome
-        Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
-
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        // Second time to make sure that settle time is overcome
-        Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
-                ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
-                false, null, false).getOpMode()).isNotEqualTo(MODE_ALLOWED);
-    }
-
     private List<PackageOps> getLoggedOps() {
         return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
new file mode 100644
index 0000000..86e12647
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
@@ -0,0 +1,910 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_WIFI_SCAN;
+import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_TOP;
+
+import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.os.Handler;
+import android.os.Message;
+import android.util.SparseArray;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.internal.os.Clock;
+import com.android.server.appop.AppOpsUidStateTracker.UidStateChangedCallback;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class AppOpsUidStateTrackerTest {
+
+    private static final int UID = 10001;
+
+    // An op code that's not location/cam/mic so that we can test the code for evaluating mode
+    // without a specific capability associated with it.
+    public static final int OP_NO_CAPABILITIES = OP_WIFI_SCAN;
+
+    @Mock
+    ActivityManagerInternal mAmi;
+
+    @Mock
+    Handler mHandler;
+
+    @Mock
+    AppOpsService.Constants mConstants;
+
+    AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock();
+
+    AppOpsUidStateTracker mIntf;
+
+    StaticMockitoSession mSession;
+
+    @Before
+    public void setUp() {
+        mSession = ExtendedMockito.mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L;
+        mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L;
+        mConstants.BG_STATE_SETTLE_TIME = 1 * 1000L;
+        mIntf = new AppOpsUidStateTrackerImpl(mAmi, mHandler, mClock, mConstants);
+    }
+
+    @After
+    public void tearDown() {
+        mSession.finishMocking();
+    }
+
+    /**
+     * This class makes the assumption that all ops are restricted at the same state, this is likely
+     * to be the case forever or become obsolete with the capability mechanism. If this fails
+     * something in {@link AppOpsUidStateTrackerImpl} might break when reporting if foreground mode
+     * might change.
+     */
+    @Test
+    public void testConstantFirstUnrestrictedUidState() {
+        for (int i = 0; i < AppOpsManager.getNumOps(); i++) {
+            assertEquals(UID_STATE_MAX_LAST_NON_RESTRICTED,
+                    AppOpsManager.resolveFirstUnrestrictedUidState(i));
+        }
+    }
+
+    @Test
+    public void testNoCapability() {
+        procStateBuilder(UID)
+                .topState()
+                .update();
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testForegroundWithMicrophoneCapability() {
+        procStateBuilder(UID)
+                .topState()
+                .microphoneCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testBackgroundWithMicrophoneCapability() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .microphoneCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testForegroundWithCameraCapability() {
+        procStateBuilder(UID)
+                .topState()
+                .cameraCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testBackgroundWithCameraCapability() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .cameraCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testForegroundWithLocationCapability() {
+        procStateBuilder(UID)
+                .topState()
+                .locationCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testBackgroundWithLocationCapability() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .locationCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testForegroundNotCapabilitiesTracked() {
+        procStateBuilder(UID)
+                .topState()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_NO_CAPABILITIES, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testBackgroundNotCapabilitiesTracked() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_NO_CAPABILITIES, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testBackgroundToForegroundTransition() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+        assertBackground(UID);
+
+        procStateBuilder(UID)
+                .topState()
+                .update();
+        assertForeground(UID);
+    }
+
+    @Test
+    public void testForegroundToBackgroundTransition() {
+        procStateBuilder(UID)
+                .topState()
+                .update();
+        assertForeground(UID);
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+        // Still in foreground due to settle time
+        assertForeground(UID);
+
+        AtomicReference<Message> messageAtomicReference = new AtomicReference<>();
+        AtomicLong delayAtomicReference = new AtomicLong();
+
+        getPostDelayedMessageArguments(messageAtomicReference, delayAtomicReference);
+        Message message = messageAtomicReference.get();
+        long delay = delayAtomicReference.get();
+
+        assertNotNull(message);
+        assertEquals(mConstants.TOP_STATE_SETTLE_TIME + 1, delay);
+
+        mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
+        message.getCallback().run();
+        assertBackground(UID);
+    }
+
+    @Test
+    public void testForegroundServiceToBackgroundTransition() {
+        procStateBuilder(UID)
+                .foregroundServiceState()
+                .update();
+        assertForeground(UID);
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+        // Still in foreground due to settle time
+        assertForeground(UID);
+
+        AtomicReference<Message> messageAtomicReference = new AtomicReference<>();
+        AtomicLong delayAtomicReference = new AtomicLong();
+
+        getPostDelayedMessageArguments(messageAtomicReference, delayAtomicReference);
+        Message message = messageAtomicReference.get();
+        long delay = delayAtomicReference.get();
+
+        assertNotNull(message);
+        assertEquals(mConstants.FG_SERVICE_STATE_SETTLE_TIME + 1, delay);
+
+        mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME + 1);
+        message.getCallback().run();
+        assertBackground(UID);
+    }
+
+    @Test
+    public void testEarlyUpdateDoesntCommit() {
+        procStateBuilder(UID)
+                .foregroundServiceState()
+                .update();
+        assertForeground(UID);
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+        // Still in foreground due to settle time
+        assertForeground(UID);
+
+        AtomicReference<Message> messageAtomicReference = new AtomicReference<>();
+
+        getPostDelayedMessageArguments(messageAtomicReference, null);
+        Message message = messageAtomicReference.get();
+
+        // 1 ms short of settle time
+        mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1);
+        message.getCallback().run();
+        assertForeground(UID);
+    }
+
+    @Test
+    public void testMicrophoneCapabilityAdded() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .microphoneCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testMicrophoneCapabilityRemoved() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .microphoneCapability()
+                .update();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testCameraCapabilityAdded() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .cameraCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testCameraCapabilityRemoved() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .cameraCapability()
+                .update();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testLocationCapabilityAdded() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .locationCapability()
+                .update();
+
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testLocationCapabilityRemoved() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .locationCapability()
+                .update();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testVisibleAppWidget() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        SparseArray<String> appPackageNames = new SparseArray<>();
+        appPackageNames.put(UID, "");
+        mIntf.updateAppWidgetVisibility(appPackageNames, true);
+
+        assertForeground(UID);
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testPendingTop() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        doReturn(true).when(mAmi).isPendingTopUid(eq(UID));
+
+        assertForeground(UID);
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testTempAllowlist() {
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        doReturn(true).when(mAmi).isTempAllowlistedForFgsWhileInUse(eq(UID));
+
+        assertForeground(UID);
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND));
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackNewProcessTop() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .topState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+
+        verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_TOP), eq(true));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackNewProcessForegroundService() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .foregroundServiceState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+
+        verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND_SERVICE), eq(true));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackNewProcessForeground() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .foregroundState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+
+        verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND), eq(true));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackNewProcessBackground() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+
+        verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_BACKGROUND), eq(false));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackNewProcessCached() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .cachedState()
+                .update();
+
+        // Cached is the default, no change in uid state.
+        verify(cb, times(0)).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
+    }
+
+    @Test
+    public void testUidStateChangedCallbackCachedToBackground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
+                ActivityManager.PROCESS_STATE_RECEIVER);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackCachedToForeground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
+                ActivityManager.PROCESS_STATE_BOUND_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackCachedToForegroundService() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackCachedToTop() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
+                ActivityManager.PROCESS_STATE_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackBackgroundToCached() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_RECEIVER,
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackBackgroundToForeground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_RECEIVER,
+                ActivityManager.PROCESS_STATE_BOUND_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackBackgroundToForegroundService() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_RECEIVER,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackBackgroundToTop() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_RECEIVER,
+                ActivityManager.PROCESS_STATE_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundToCached() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_BOUND_TOP,
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundToBackground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_BOUND_TOP,
+                ActivityManager.PROCESS_STATE_RECEIVER);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundToForegroundService() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_BOUND_TOP,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundToTop() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_BOUND_TOP,
+                ActivityManager.PROCESS_STATE_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundServiceToCached() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundServiceToBackground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_STATE_RECEIVER);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundServiceToForeground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_STATE_BOUND_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundServiceToTop() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_STATE_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackTopToCached() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackTopToBackground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_STATE_RECEIVER);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackTopToForeground() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_STATE_BOUND_TOP);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackTopToForegroundService() {
+        testUidStateChangedCallback(
+                ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+    }
+
+    @Test
+    public void testUidStateChangedCallbackCachedToNonexistent() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .cachedState()
+                .update();
+
+        procStateBuilder(UID)
+                .nonExistentState()
+                .update();
+
+        verify(mHandler, never()).post(any());
+        verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean());
+    }
+
+    @Test
+    public void testUidStateChangedCallbackBackgroundToNonexistent() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .backgroundState()
+                .update();
+
+        procStateBuilder(UID)
+                .nonExistentState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+        verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(false));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundToNonexistent() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .foregroundState()
+                .update();
+
+        procStateBuilder(UID)
+                .nonExistentState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+        verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackForegroundServiceToNonexistent() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .foregroundServiceState()
+                .update();
+
+        procStateBuilder(UID)
+                .nonExistentState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+        verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
+    }
+
+    @Test
+    public void testUidStateChangedCallbackTopToNonexistent() {
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .topState()
+                .update();
+
+        procStateBuilder(UID)
+                .nonExistentState()
+                .update();
+
+        getLatestPostMessageArgument().getCallback().run();
+        verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true));
+    }
+
+    public void testUidStateChangedCallback(int initialState, int finalState) {
+        int initialUidState = processStateToUidState(initialState);
+        int finalUidState = processStateToUidState(finalState);
+        boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
+                        != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
+        boolean finalUidStateIsBackgroundAndLessImportant =
+                finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED
+                        && finalUidState > initialUidState;
+
+        UidStateChangedCallback cb = addUidStateChangeCallback();
+
+        procStateBuilder(UID)
+                .setState(initialState)
+                .update();
+
+        procStateBuilder(UID)
+                .setState(finalState)
+                .update();
+
+        if (finalUidStateIsBackgroundAndLessImportant) {
+            AtomicReference<Message> delayedMessage = new AtomicReference<>();
+            getPostDelayedMessageArguments(delayedMessage, new AtomicLong());
+            mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1);
+            delayedMessage.get().getCallback().run();
+        }
+
+        getLatestPostMessageArgument().getCallback().run();
+        verify(cb, atLeastOnce())
+                .onUidStateChanged(eq(UID), eq(finalUidState), eq(foregroundChange));
+    }
+
+    private UidStateChangedCallback addUidStateChangeCallback() {
+        UidStateChangedCallback cb =
+                Mockito.mock(UidStateChangedCallback.class);
+        mIntf.addUidStateChangedCallback(mHandler, cb);
+        return cb;
+    }
+
+    /* If testForegroundNotCapabilitiesTracked fails, this assertion is probably incorrect */
+    private void assertForeground(int uid) {
+        assertEquals(MODE_ALLOWED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND));
+    }
+
+    /* If testBackgroundNotCapabilitiesTracked fails, this assertion is probably incorrect */
+    private void assertBackground(int uid) {
+        assertEquals(MODE_IGNORED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND));
+    }
+
+    private void getPostDelayedMessageArguments(AtomicReference<Message> message,
+            AtomicLong delay) {
+
+        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
+
+        verify(mHandler).sendMessageDelayed(messageCaptor.capture(), delayCaptor.capture());
+
+        if (message != null) {
+            message.set(messageCaptor.getValue());
+        }
+        if (delay != null) {
+            delay.set(delayCaptor.getValue());
+        }
+    }
+
+    private Message getLatestPostMessageArgument() {
+        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+
+        verify(mHandler, atLeast(1)).sendMessage(messageCaptor.capture());
+
+        return messageCaptor.getValue();
+    }
+
+    private UidProcStateUpdateBuilder procStateBuilder(int uid) {
+        return new UidProcStateUpdateBuilder(mIntf, uid);
+    }
+
+    private static class UidProcStateUpdateBuilder {
+        private AppOpsUidStateTracker mIntf;
+        private int mUid;
+        private int mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+        private int mCapability = 0;
+
+        private UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid) {
+            mUid = uid;
+            mIntf = intf;
+        }
+
+        public void update() {
+            mIntf.updateUidProcState(mUid, mProcState, mCapability);
+        }
+
+        public UidProcStateUpdateBuilder persistentState() {
+            mProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder setState(int procState) {
+            mProcState = procState;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder topState() {
+            mProcState = ActivityManager.PROCESS_STATE_TOP;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder foregroundServiceState() {
+            mProcState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder foregroundState() {
+            mProcState = ActivityManager.PROCESS_STATE_BOUND_TOP;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder backgroundState() {
+            mProcState = ActivityManager.PROCESS_STATE_SERVICE;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder cachedState() {
+            mProcState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder nonExistentState() {
+            mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder locationCapability() {
+            mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder cameraCapability() {
+            mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+            return this;
+        }
+
+        public UidProcStateUpdateBuilder microphoneCapability() {
+            mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+            return this;
+        }
+    }
+
+    private static class AppOpsUidStateTrackerTestClock extends Clock {
+
+        long mElapsedRealTime = 0x5f3759df;
+
+        @Override
+        public long elapsedRealtime() {
+            return mElapsedRealTime;
+        }
+
+        void advanceTime(long time) {
+            mElapsedRealTime += time;
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 6a18dc1..9a4bb22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -233,4 +233,4 @@
                 });
         when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
     }
-}
+}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index efc1b58..bb5b1d8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -62,7 +62,7 @@
 import com.android.server.extendedtestutils.wheneverStatic
 import com.android.server.pm.dex.DexManager
 import com.android.server.pm.parsing.PackageParser2
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.parsing.pkg.ParsedPackage
 import com.android.server.pm.permission.PermissionManagerServiceInternal
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
index c9b36f0..987192d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
@@ -21,7 +21,7 @@
 import android.os.Build
 import android.os.Process
 import android.util.Log
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.testutils.whenever
 import org.hamcrest.MatcherAssert.assertThat
 import org.hamcrest.Matchers.equalTo
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index e59a404..8744f32 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -28,7 +28,7 @@
 import com.android.server.compat.PlatformCompat
 import com.android.server.extendedtestutils.wheneverStatic
 import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.parsing.pkg.ParsedPackage
 import com.android.server.testutils.any
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
new file mode 100644
index 0000000..245b4dc
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.pm.UserManagerInternal.PARENT_DISPLAY;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.util.Log;
+
+import org.junit.Test;
+
+/**
+ * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerInternalTest}
+ */
+public final class UserManagerInternalTest extends UserManagerServiceOrInternalTestCase {
+
+    private static final String TAG = UserManagerInternalTest.class.getSimpleName();
+
+    // NOTE: most the tests below only apply to MUMD configurations, so we're not adding _mumd_
+    // in the test names, but _nonMumd_ instead
+
+    @Test
+    public void testAssignUserToDisplay_nonMumd_defaultDisplayIgnored() {
+        mUmi.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);
+
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Test
+    public void testAssignUserToDisplay_nonMumd_otherDisplay_currentUser() {
+        mockCurrentUser(USER_ID);
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
+    }
+
+    @Test
+    public void testAssignUserToDisplay_nonMumd_otherDisplay_startProfileOfcurrentUser() {
+        mockCurrentUser(PARENT_USER_ID);
+        addDefaultProfileAndParent();
+        startDefaultProfile();
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+    }
+
+    @Test
+    public void testAssignUserToDisplay_nonMumd_otherDisplay_stoppedProfileOfcurrentUser() {
+        mockCurrentUser(PARENT_USER_ID);
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+    }
+
+    @Test
+    public void testAssignUserToDisplay_defaultDisplayIgnored() {
+        enableUsersOnSecondaryDisplays();
+
+        mUmi.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);
+
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Test
+    public void testAssignUserToDisplay_systemUser() {
+        enableUsersOnSecondaryDisplays();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID));
+    }
+
+    @Test
+    public void testAssignUserToDisplay_invalidDisplay() {
+        enableUsersOnSecondaryDisplays();
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(USER_ID, INVALID_DISPLAY));
+    }
+
+    @Test
+    public void testAssignUserToDisplay_currentUser() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(USER_ID);
+
+        assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
+
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Test
+    public void testAssignUserToDisplay_startedProfileOfCurrentUser() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(PARENT_USER_ID);
+        addDefaultProfileAndParent();
+        startDefaultProfile();
+
+        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+
+        Log.v(TAG, "Exception: " + e);
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Test
+    public void testAssignUserToDisplay_stoppedProfileOfCurrentUser() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(PARENT_USER_ID);
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
+
+        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+
+        Log.v(TAG, "Exception: " + e);
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Test
+    public void testAssignUserToDisplay_displayAvailable() {
+        enableUsersOnSecondaryDisplays();
+
+        mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertUserAssignedToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+    }
+
+    @Test
+    public void testAssignUserToDisplay_displayAlreadyAssigned() {
+        enableUsersOnSecondaryDisplays();
+
+        mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        IllegalStateException e = assertThrows(IllegalStateException.class,
+                () -> mUmi.assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID));
+
+        Log.v(TAG, "Exception: " + e);
+        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+                .matches("Cannot.*" + OTHER_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*already.*"
+                        + USER_ID + ".*");
+    }
+
+    @Test
+    public void testAssignUserToDisplay_userAlreadyAssigned() {
+        enableUsersOnSecondaryDisplays();
+
+        mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        IllegalStateException e = assertThrows(IllegalStateException.class,
+                () -> mUmi.assignUserToDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID));
+
+        Log.v(TAG, "Exception: " + e);
+        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+                .matches("Cannot.*" + USER_ID + ".*" + OTHER_SECONDARY_DISPLAY_ID + ".*already.*"
+                        + SECONDARY_DISPLAY_ID + ".*");
+
+        assertUserAssignedToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+    }
+
+    @Test
+    public void testAssignUserToDisplay_profileOnSameDisplayAsParent() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+
+        mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+        mUmi.assignUserToDisplay(PROFILE_USER_ID, PARENT_DISPLAY);
+
+        assertUsersAssignedToDisplays(PARENT_USER_ID, SECONDARY_DISPLAY_ID,
+                pair(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+    }
+
+    @Test
+    public void testAssignUserToDisplay_profileOnDifferentDisplayAsParent() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+
+        mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+
+        Log.v(TAG, "Exception: " + e);
+        assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+    }
+
+    @Test
+    public void testUnassignUserFromDisplay_nonMumd_ignored() {
+        mockCurrentUser(USER_ID);
+
+        mUmi.unassignUserFromDisplay(USER_SYSTEM);
+        mUmi.unassignUserFromDisplay(USER_ID);
+        mUmi.unassignUserFromDisplay(OTHER_USER_ID);
+
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Test
+    public void testUnassignUserFromDisplay() {
+        testAssignUserToDisplay_displayAvailable();
+
+        mUmi.unassignUserFromDisplay(USER_ID);
+
+        assertNoUserAssignedToDisplay();
+    }
+
+    @Override
+    protected boolean isUserVisible(int userId) {
+        return mUmi.isUserVisible(userId);
+    }
+
+    @Override
+    protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+        return mUmi.isUserVisible(userId, displayId);
+    }
+
+    @Override
+    protected int getDisplayAssignedToUser(int userId) {
+        return mUmi.getDisplayAssignedToUser(userId);
+    }
+
+    @Override
+    protected int getUserAssignedToDisplay(int displayId) {
+        return mUmi.getUserAssignedToDisplay(displayId);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
new file mode 100644
index 0000000..6f0efb0
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static android.os.UserHandle.USER_NULL;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import androidx.test.annotation.UiThreadTest;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.server.ExtendedMockitoTestCase;
+import com.android.server.LocalServices;
+import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerService.UserData;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Base class for {@link UserManagerInternalTest} and {@link UserManagerInternalTest}.
+ *
+ * <p>{@link UserManagerService} and its {@link UserManagerInternal} implementation have a
+ * "symbiotic relationship - some methods of the former simply call the latter and vice versa.
+ *
+ * <p>Ideally, only one of them should have the logic, but since that's not the case, this class
+ * provices the infra to make it easier to test both (which in turn would make it easier / safer to
+ * refactor their logic later).
+ */
+abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestCase {
+
+    private static final String TAG = UserManagerServiceOrInternalTestCase.class.getSimpleName();
+
+    /**
+     * Id for a simple user (that doesn't have profiles).
+     */
+    protected static final int USER_ID = 600;
+
+    /**
+     * Id for another simple user.
+     */
+    protected static final int OTHER_USER_ID = 666;
+
+    /**
+     * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
+     *
+     * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+     */
+    protected static final int PARENT_USER_ID = 642;
+
+    /**
+     * Id for a profile whose parent is {@link #PARENTUSER_ID}.
+     *
+     * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+     */
+    protected static final int PROFILE_USER_ID = 643;
+
+    /**
+     * Id of a secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
+     */
+    protected static final int SECONDARY_DISPLAY_ID = 42;
+
+    /**
+     * Id of another secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
+     */
+    protected static final int OTHER_SECONDARY_DISPLAY_ID = 108;
+
+    private final Object mPackagesLock = new Object();
+    private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
+    private final SparseArray<UserData> mUsers = new SparseArray<>();
+
+    // TODO(b/244644281): manipulating mUsersOnSecondaryDisplays directly leaks implementation
+    // details into the unit test, but it's fine for now - in the long term, this logic should be
+    // refactored into a proper UserDisplayAssignment class.
+    private final SparseIntArray mUsersOnSecondaryDisplays = new SparseIntArray();
+
+    private Context mSpiedContext;
+    private UserManagerService mStandardUms;
+    private UserManagerService mMumdUms;
+    private UserManagerInternal mStandardUmi;
+    private UserManagerInternal mMumdUmi;
+
+    private @Mock PackageManagerService mMockPms;
+    private @Mock UserDataPreparer mMockUserDataPreparer;
+    private @Mock ActivityManagerInternal mActivityManagerInternal;
+
+    /**
+     * Reference to the {@link UserManagerService} being tested.
+     *
+     * <p>By default, such service doesn't support {@code MUMD} (Multiple Users on Multiple
+     * Displays), but that can be changed by calling {@link #enableUsersOnSecondaryDisplays()}.
+     */
+    protected UserManagerService mUms;
+
+    /**
+     * Reference to the {@link UserManagerInternal} being tested.
+     *
+     * <p>By default, such service doesn't support {@code MUMD} (Multiple Users on Multiple
+     * Displays), but that can be changed by calling {@link #enableUsersOnSecondaryDisplays()}.
+     */
+    protected UserManagerInternal mUmi;
+
+    @Override
+    protected void initializeSession(StaticMockitoSessionBuilder builder) {
+        builder
+                .spyStatic(UserManager.class)
+                .spyStatic(LocalServices.class);
+    }
+
+    @Before
+    @UiThreadTest // Needed to initialize main handler
+    public final void setFixtures() {
+        mSpiedContext = spy(mRealContext);
+
+        // Called when WatchedUserStates is constructed
+        doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
+
+        // Need to set both UserManagerService instances here, as they need to be run in the
+        // UiThread
+
+        // mMumdUms / mMumdUmi
+        mockIsUsersOnSecondaryDisplaysEnabled(/* usersOnSecondaryDisplaysEnabled= */ true);
+        mMumdUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+                mPackagesLock, mRealContext.getDataDir(), mUsers, mUsersOnSecondaryDisplays);
+        assertWithMessage("UserManagerService.isUsersOnSecondaryDisplaysEnabled()")
+                .that(mMumdUms.isUsersOnSecondaryDisplaysEnabled())
+                .isTrue();
+        mMumdUmi = LocalServices.getService(UserManagerInternal.class);
+        assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mMumdUmi)
+                .isNotNull();
+        resetUserManagerInternal();
+
+        // mStandardUms / mStandardUmi
+        mockIsUsersOnSecondaryDisplaysEnabled(/* usersOnSecondaryDisplaysEnabled= */ false);
+        mStandardUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+                mPackagesLock, mRealContext.getDataDir(), mUsers, mUsersOnSecondaryDisplays);
+        assertWithMessage("UserManagerService.isUsersOnSecondaryDisplaysEnabled()")
+                .that(mStandardUms.isUsersOnSecondaryDisplaysEnabled())
+                .isFalse();
+        mStandardUmi = LocalServices.getService(UserManagerInternal.class);
+        assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mStandardUmi)
+                .isNotNull();
+        setServiceFixtures(/*usersOnSecondaryDisplaysEnabled= */ false);
+    }
+
+    @After
+    public final void resetUserManagerInternal() {
+        // LocalServices follows the "Highlander rule" - There can be only one!
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+    }
+
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    // Methods whose UMS implementation calls UMI or vice-versa - they're tested in this class, //
+    // but the subclass must provide the proper implementation                                  //
+    //////////////////////////////////////////////////////////////////////////////////////////////
+
+    protected abstract boolean isUserVisible(int userId);
+    protected abstract boolean isUserVisibleOnDisplay(int userId, int displayId);
+    protected abstract int getDisplayAssignedToUser(int userId);
+    protected abstract int getUserAssignedToDisplay(int displayId);
+
+    /////////////////////////////////
+    // Tests for the above methods //
+    /////////////////////////////////
+
+    @Test
+    public void testIsUserVisible_invalidUser() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisible(%s)", USER_NULL).that(isUserVisible(USER_NULL)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisible_currentUser() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisible_nonCurrentUser() {
+        mockCurrentUser(OTHER_USER_ID);
+
+        assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisible_startedProfileOfcurrentUser() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        startDefaultProfile();
+        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+        assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID).that(isUserVisible(PROFILE_USER_ID))
+                .isTrue();
+    }
+
+    @Test
+    public void testIsUserVisible_stoppedProfileOfcurrentUser() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        stopDefaultProfile();
+
+        assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID).that(isUserVisible(PROFILE_USER_ID))
+                .isFalse();
+    }
+
+    @Test
+    public void testIsUserVisible_bgUserOnSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(OTHER_USER_ID);
+        assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isTrue();
+    }
+
+    // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+    // isUserVisible() for bg users relies only on the user / display assignments
+
+    @Test
+    public void testIsUserVisibleOnDisplay_invalidUser() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_NULL, DEFAULT_DISPLAY)
+                .that(isUserVisibleOnDisplay(USER_NULL, DEFAULT_DISPLAY)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_currentUserInvalidDisplay() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, INVALID_DISPLAY)
+                .that(isUserVisibleOnDisplay(USER_ID, INVALID_DISPLAY)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_currentUserDefaultDisplay() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+                .that(isUserVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_currentUserSecondaryDisplay() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_currentUserUnassignedSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_currentUserSecondaryDisplayAssignedToAnotherUser() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(USER_ID);
+        assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_startedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+        startDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
+        assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_stoppedProfileOfCurrentUserSecondaryDisplayAssignedToAnotherUser() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
+        assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_nonCurrentUserDefaultDisplay() {
+        mockCurrentUser(OTHER_USER_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+                .that(isUserVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserInvalidDisplay() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        startDefaultProfile();
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserInvalidDisplay() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        stopDefaultProfile();
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserDefaultDisplay() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        startDefaultProfile();
+        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserDefaultDisplay() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        stopDefaultProfile();
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserSecondaryDisplay() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        startDefaultProfile();
+        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserSecondaryDisplay() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        stopDefaultProfile();
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_bgUserOnSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(OTHER_USER_ID);
+        assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsUserVisibleOnDisplay_mumd_bgUserOnAnotherSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(OTHER_USER_ID);
+        assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+                .that(isUserVisibleOnDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID)).isFalse();
+    }
+
+    // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+    // isUserVisibleOnDisplay() for bg users relies only on the user / display assignments
+
+    @Test
+    public void testGetDisplayAssignedToUser_invalidUser() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getDisplayAssignedToUser(%s)", USER_NULL)
+                .that(getDisplayAssignedToUser(USER_NULL)).isEqualTo(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testGetDisplayAssignedToUser_currentUser() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+                .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testGetDisplayAssignedToUser_nonCurrentUser() {
+        mockCurrentUser(OTHER_USER_ID);
+
+        assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+                .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testGetDisplayAssignedToUser_startedProfileOfcurrentUser() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        startDefaultProfile();
+        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+        assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
+                .that(getDisplayAssignedToUser(PROFILE_USER_ID)).isEqualTo(DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testGetDisplayAssignedToUser_stoppedProfileOfcurrentUser() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(PARENT_USER_ID);
+        stopDefaultProfile();
+
+        assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
+                .that(getDisplayAssignedToUser(PROFILE_USER_ID)).isEqualTo(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testGetDisplayAssignedToUser_bgUserOnSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(OTHER_USER_ID);
+        assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+                .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(SECONDARY_DISPLAY_ID);
+    }
+
+    // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+    // getDisplayAssignedToUser() for bg users relies only on the user / display assignments
+
+    @Test
+    public void testGetUserAssignedToDisplay_invalidDisplay() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getUserAssignedToDisplay(%s)", INVALID_DISPLAY)
+                .that(getUserAssignedToDisplay(INVALID_DISPLAY)).isEqualTo(USER_ID);
+    }
+
+    @Test
+    public void testGetUserAssignedToDisplay_defaultDisplay() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getUserAssignedToDisplay(%s)", DEFAULT_DISPLAY)
+                .that(getUserAssignedToDisplay(DEFAULT_DISPLAY)).isEqualTo(USER_ID);
+    }
+
+    @Test
+    public void testGetUserAssignedToDisplay_secondaryDisplay() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID)
+                .that(getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID);
+    }
+
+    @Test
+    public void testGetUserAssignedToDisplay_mumd_bgUserOnSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(OTHER_USER_ID);
+        assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID)
+                .that(getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID);
+    }
+
+    @Test
+    public void testGetUserAssignedToDisplay_mumd_noUserOnSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID)
+                .that(getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID);
+    }
+
+    // TODO(b/244644281): scenario below shouldn't happen on "real life", as the profile cannot be
+    // started on secondary display if its parent isn't, so we might need to remove (or refactor
+    // this test) if/when the underlying logic changes
+    @Test
+    public void testGetUserAssignedToDisplay_mumd_profileOnSecondaryDisplay() {
+        enableUsersOnSecondaryDisplays();
+        addDefaultProfileAndParent();
+        mockCurrentUser(USER_ID);
+        assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+        assertWithMessage("getUserAssignedToDisplay(%s)", SECONDARY_DISPLAY_ID)
+                .that(getUserAssignedToDisplay(SECONDARY_DISPLAY_ID)).isEqualTo(USER_ID);
+    }
+
+    // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+    // getUserAssignedToDisplay() for bg users relies only on the user / display assignments
+
+
+    ///////////////////////////////////////////
+    // Helper methods exposed to sub-classes //
+    ///////////////////////////////////////////
+
+    /**
+     * Change test fixtures to use a version that supports {@code MUMD} (Multiple Users on Multiple
+     * Displays).
+     */
+    protected final void enableUsersOnSecondaryDisplays() {
+        setServiceFixtures(/* usersOnSecondaryDisplaysEnabled= */ true);
+    }
+
+    protected final void mockCurrentUser(@UserIdInt int userId) {
+        mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
+
+        when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
+    }
+
+    protected final <T> void mockGetLocalService(Class<T> serviceClass, T service) {
+        doReturn(service).when(() -> LocalServices.getService(serviceClass));
+    }
+
+    protected final void addDefaultProfileAndParent() {
+        addUser(PARENT_USER_ID);
+        addProfile(PROFILE_USER_ID, PARENT_USER_ID);
+    }
+
+    protected final void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
+        TestUserData profileData = new TestUserData(profileId);
+        profileData.info.flags = UserInfo.FLAG_PROFILE;
+        profileData.info.profileGroupId = parentId;
+
+        addUserData(profileData);
+    }
+
+    protected final void addUser(@UserIdInt int userId) {
+        TestUserData userData = new TestUserData(userId);
+
+        addUserData(userData);
+    }
+
+    protected final void startDefaultProfile() {
+        startUser(PROFILE_USER_ID);
+    }
+
+    protected final void stopDefaultProfile() {
+        stopUser(PROFILE_USER_ID);
+    }
+
+    protected final void startUser(@UserIdInt int userId) {
+        setUserState(userId, UserState.STATE_RUNNING_UNLOCKED);
+    }
+
+    protected final void stopUser(@UserIdInt int userId) {
+        setUserState(userId, UserState.STATE_STOPPING);
+    }
+
+    // NOTE: should only called by tests that indirectly needs to check user assignments (like
+    // isUserVisible), not by tests for the user assignment methods per se.
+    protected final void assignUserToDisplay(@UserIdInt int userId, int displayId) {
+        mUsersOnSecondaryDisplays.put(userId, displayId);
+    }
+
+    protected final void assertNoUserAssignedToDisplay() {
+        assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
+                .isEmpty();
+    }
+
+    protected final void assertUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
+        assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
+                .containsExactly(userId, displayId);
+    }
+
+    @SafeVarargs
+    protected final void assertUsersAssignedToDisplays(@UserIdInt int userId, int displayId,
+            @SuppressWarnings("unchecked") Pair<Integer, Integer>... others) {
+        Object[] otherObjects = new Object[others.length * 2];
+        for (int i = 0; i < others.length; i++) {
+            Pair<Integer, Integer> other = others[i];
+            otherObjects[i * 2] = other.first;
+            otherObjects[i * 2 + 1] = other.second;
+
+        }
+        assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
+                .containsExactly(userId, displayId, otherObjects);
+    }
+
+    protected static Pair<Integer, Integer> pair(@UserIdInt int userId, int secondaryDisplayId) {
+        return new Pair<>(userId, secondaryDisplayId);
+    }
+
+    ///////////////////
+    // Private infra //
+    ///////////////////
+
+    private void setServiceFixtures(boolean usersOnSecondaryDisplaysEnabled) {
+        Log.d(TAG, "Setting fixtures for usersOnSecondaryDisplaysEnabled="
+                + usersOnSecondaryDisplaysEnabled);
+        if (usersOnSecondaryDisplaysEnabled) {
+            mUms = mMumdUms;
+            mUmi = mMumdUmi;
+        } else {
+            mUms = mStandardUms;
+            mUmi = mStandardUmi;
+        }
+    }
+
+    private void mockIsUsersOnSecondaryDisplaysEnabled(boolean enabled) {
+        Log.d(TAG, "Mocking UserManager.isUsersOnSecondaryDisplaysEnabled() to return " + enabled);
+        doReturn(enabled).when(() -> UserManager.isUsersOnSecondaryDisplaysEnabled());
+    }
+
+    private void addUserData(TestUserData userData) {
+        Log.d(TAG, "Adding " + userData);
+        mUsers.put(userData.info.id, userData);
+    }
+
+    private void setUserState(@UserIdInt int userId, int userState) {
+        mUmi.setUserState(userId, userState);
+    }
+
+    private void removeUserState(@UserIdInt int userId) {
+        mUmi.removeUserState(userId);
+    }
+
+    private Map<Integer, Integer> usersOnSecondaryDisplaysAsMap() {
+        int size = mUsersOnSecondaryDisplays.size();
+        Map<Integer, Integer> map = new LinkedHashMap<>(size);
+        for (int i = 0; i < size; i++) {
+            map.put(mUsersOnSecondaryDisplays.keyAt(i), mUsersOnSecondaryDisplays.valueAt(i));
+        }
+        return map;
+    }
+
+    private static final class TestUserData extends UserData {
+
+        @SuppressWarnings("deprecation")
+        TestUserData(@UserIdInt int userId) {
+            info = new UserInfo();
+            info.id = userId;
+        }
+
+        @Override
+        public String toString() {
+            return "TestUserData[" + info.toFullString() + "]";
+        }
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6493111..8b5921c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -15,87 +15,20 @@
  */
 package com.android.server.pm;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
-import android.content.Context;
-import android.content.pm.UserInfo;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.SparseArray;
 
-import androidx.test.annotation.UiThreadTest;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
-import com.android.server.ExtendedMockitoTestCase;
-import com.android.server.LocalServices;
-import com.android.server.am.UserState;
-import com.android.server.pm.UserManagerService.UserData;
-
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mock;
 
 /**
  * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest}
  */
-public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
-
-    private static final String TAG = UserManagerServiceTest.class.getSimpleName();
-
-    private final Object mPackagesLock = new Object();
-    private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
-    private Context mSpiedContext;
-
-    private @Mock PackageManagerService mMockPms;
-    private @Mock UserDataPreparer mMockUserDataPreparer;
-    private @Mock ActivityManagerInternal mActivityManagerInternal;
-
-    private final SparseArray<UserData> mUsers = new SparseArray<>();
-    private UserManagerService mUms;
-    private UserManagerInternal mUmi;
-
-    @Override
-    protected void initializeSession(StaticMockitoSessionBuilder builder) {
-        builder
-                .spyStatic(UserManager.class)
-                .spyStatic(LocalServices.class);
-    }
-
-    @Before
-    @UiThreadTest // Needed to initialize main handler
-    public void setFixtures() {
-        mSpiedContext = spy(mRealContext);
-
-        // Called when WatchedUserStates is constructed
-        doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
-
-        mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
-                mPackagesLock, mRealContext.getDataDir(), mUsers);
-        mUmi = LocalServices.getService(UserManagerInternal.class);
-
-        assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mUmi)
-                .isNotNull();
-    }
-
-    @After
-    public void resetLocalService() {
-        // LocalServices follows the "Highlander rule" - There can be only one!
-        LocalServices.removeServiceForTest(UserManagerInternal.class);
-    }
+public final class UserManagerServiceTest extends UserManagerServiceOrInternalTestCase {
 
     @Test
-    public void testgetCurrentUserId_amInternalNotReady() {
+    public void testGetCurrentUserId_amInternalNotReady() {
         mockGetLocalService(ActivityManagerInternal.class, null);
 
         assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
@@ -103,119 +36,111 @@
     }
 
     @Test
-    public void testgetCurrentUserId() {
-        mockCurrentUser(42);
+    public void testGetCurrentUserId() {
+        mockCurrentUser(USER_ID);
 
         assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
-                .isEqualTo(42);
+                .isEqualTo(USER_ID);
     }
 
     @Test
     public void testIsCurrentUserOrRunningProfileOfCurrentUser_currentUser() {
-        int userId = 42;
-        mockCurrentUser(userId);
+        mockCurrentUser(USER_ID);
 
-        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
-                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(userId)).isTrue();
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isTrue();
     }
 
     @Test
     public void testIsCurrentUserOrRunningProfileOfCurrentUser_notCurrentUser() {
-        int userId = 42;
-        mockCurrentUser(108);
+        mockCurrentUser(OTHER_USER_ID);
 
-        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
-                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(userId)).isFalse();
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isFalse();
     }
 
     @Test
     public void testIsCurrentUserOrRunningProfileOfCurrentUser_startedProfileOfCurrentUser() {
-        int parentId = 108;
-        int profileId = 42;
-        addUser(parentId);
-        addProfile(profileId, parentId);
-        mockCurrentUser(parentId);
-        setUserState(profileId, UserState.STATE_RUNNING_UNLOCKED);
+        addDefaultProfileAndParent();
+        startDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
 
-        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
-                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isTrue();
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isTrue();
     }
 
     @Test
     public void testIsCurrentUserOrRunningProfileOfCurrentUser_stoppedProfileOfCurrentUser() {
-        int parentId = 108;
-        int profileId = 42;
-        addUser(parentId);
-        addProfile(profileId, parentId);
-        mockCurrentUser(parentId);
-        // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
-        removeUserState(profileId);
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
 
-        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
-                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isFalse();
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
     }
 
     @Test
     public void testIsCurrentUserOrRunningProfileOfCurrentUser_profileOfNonCurrentUSer() {
-        int parentId = 108;
-        int profileId = 42;
-        int currentUserId = 666;
-        addUser(parentId);
-        addProfile(profileId, parentId);
-        mockCurrentUser(currentUserId);
+        addDefaultProfileAndParent();
+        mockCurrentUser(OTHER_USER_ID);
 
-        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
-                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isFalse();
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
     }
 
-    private void mockCurrentUser(@UserIdInt int userId) {
-        mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
+    @Test
+    public void testIsUserRunning_StartedUserShouldReturnTrue() {
+        addUser(USER_ID);
+        startUser(USER_ID);
 
-        when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
+        assertWithMessage("isUserRunning(%s)", USER_ID)
+                .that(mUms.isUserRunning(USER_ID)).isTrue();
     }
 
-    private <T> void mockGetLocalService(Class<T> serviceClass, T service) {
-        doReturn(service).when(() -> LocalServices.getService(serviceClass));
+    @Test
+    public void testIsUserRunning_StoppedUserShouldReturnFalse() {
+        addUser(USER_ID);
+        stopUser(USER_ID);
+
+        assertWithMessage("isUserRunning(%s)", USER_ID)
+                .that(mUms.isUserRunning(USER_ID)).isFalse();
     }
 
-    private void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
-        TestUserData profileData = new TestUserData(profileId);
-        profileData.info.flags = UserInfo.FLAG_PROFILE;
-        profileData.info.profileGroupId = parentId;
+    @Test
+    public void testIsUserRunning_CurrentUserStartedWorkProfileShouldReturnTrue() {
+        addDefaultProfileAndParent();
+        startDefaultProfile();
 
-        addUserData(profileData);
+        assertWithMessage("isUserRunning(%s)", PROFILE_USER_ID)
+                .that(mUms.isUserRunning(PROFILE_USER_ID)).isTrue();
     }
 
-    private void addUser(@UserIdInt int userId) {
-        TestUserData userData = new TestUserData(userId);
+    @Test
+    public void testIsUserRunning_CurrentUserStoppedWorkProfileShouldReturnFalse() {
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
 
-        addUserData(userData);
+        assertWithMessage("isUserRunning(%s)", PROFILE_USER_ID)
+                .that(mUms.isUserRunning(PROFILE_USER_ID)).isFalse();
     }
 
-    private void addUserData(TestUserData userData) {
-        Log.d(TAG, "Adding " + userData);
-        mUsers.put(userData.info.id, userData);
+    @Override
+    protected boolean isUserVisible(int userId) {
+        return mUms.isUserVisibleUnchecked(userId);
     }
 
-    private void setUserState(@UserIdInt int userId, int userState) {
-        mUmi.setUserState(userId, userState);
+    @Override
+    protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+        return mUms.isUserVisibleOnDisplay(userId, displayId);
     }
 
-    private void removeUserState(@UserIdInt int userId) {
-        mUmi.removeUserState(userId);
+    @Override
+    protected int getDisplayAssignedToUser(int userId) {
+        return mUms.getDisplayAssignedToUser(userId);
     }
 
-    private static final class TestUserData extends UserData {
-
-        @SuppressWarnings("unused")
-        TestUserData(@UserIdInt int userId) {
-            info = new UserInfo();
-            info.id = userId;
-        }
-
-        @Override
-        public String toString() {
-            return "TestUserData[" + info.toFullString() + "]";
-        }
+    @Override
+    protected int getUserAssignedToDisplay(int displayId) {
+        return mUms.getUserAssignedToDisplay(displayId);
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 831a69a..94fff22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.tare.TareTestUtils.assertLedgersEqual;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -89,6 +90,33 @@
     }
 
     @Test
+    public void testAppRemoval() {
+        final long consumptionLimit = 1_000_000L;
+        final long remainingCakes = consumptionLimit / 2;
+        mScribe.setConsumptionLimitLocked(consumptionLimit);
+        mScribe.adjustRemainingConsumableCakesLocked(remainingCakes - consumptionLimit);
+        assertEquals(remainingCakes, mScribe.getRemainingConsumableCakesLocked());
+
+        final int userId = 0;
+        final String pkgName = "com.test";
+        final Agent agent = new Agent(mIrs, mScribe, mAnalyst);
+        final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
+
+        doReturn(consumptionLimit).when(mIrs).getConsumptionLimitLocked();
+        doReturn(consumptionLimit).when(mEconomicPolicy)
+                .getMaxSatiatedBalance(anyInt(), anyString());
+
+        Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 10);
+        agent.recordTransactionLocked(userId, pkgName, ledger, transaction, false);
+        assertEquals(5, ledger.getCurrentBalance());
+        assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
+
+        agent.onPackageRemovedLocked(userId, pkgName);
+        assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
+        assertLedgersEqual(new Ledger(), mScribe.getLedgerLocked(userId, pkgName));
+    }
+
+    @Test
     public void testRecordTransaction_UnderMax() {
         Agent agent = new Agent(mIrs, mScribe, mAnalyst);
         Ledger ledger = new Ledger();
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java
new file mode 100644
index 0000000..29bddfc
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class EconomicPolicyTest {
+
+    @Test
+    public void testMasksDisjoint() {
+        assertEquals(-1,
+                (-1 & EconomicPolicy.MASK_TYPE)
+                        + (-1 & EconomicPolicy.MASK_POLICY)
+                        + (-1 & EconomicPolicy.MASK_EVENT));
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index 5cf026e..4ce268f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.tare.TareTestUtils.assertLedgersEqual;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -30,7 +31,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArrayMap;
-import android.util.SparseLongArray;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -345,43 +345,6 @@
         assertEquals(900, mScribeUnderTest.getRemainingConsumableCakesLocked());
     }
 
-    private void assertLedgersEqual(Ledger expected, Ledger actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
-
-        List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
-        List<Ledger.Transaction> actualTransactions = actual.getTransactions();
-        assertEquals(expectedTransactions.size(), actualTransactions.size());
-        for (int i = 0; i < expectedTransactions.size(); ++i) {
-            assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
-        }
-
-        List<Ledger.RewardBucket> expectedRewardBuckets = expected.getRewardBuckets();
-        List<Ledger.RewardBucket> actualRewardBuckets = actual.getRewardBuckets();
-        assertEquals(expectedRewardBuckets.size(), actualRewardBuckets.size());
-        for (int i = 0; i < expectedRewardBuckets.size(); ++i) {
-            assertRewardBucketsEqual(expectedRewardBuckets.get(i), actualRewardBuckets.get(i));
-        }
-    }
-
-    private void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        final int size = expected.size();
-        assertEquals(size, actual.size());
-        for (int i = 0; i < size; ++i) {
-            assertEquals(expected.keyAt(i), actual.keyAt(i));
-            assertEquals(expected.valueAt(i), actual.valueAt(i));
-        }
-    }
-
     private void assertReportListsEqual(List<Analyst.Report> expected,
             List<Analyst.Report> actual) {
         if (expected == null) {
@@ -425,31 +388,6 @@
         }
     }
 
-    private void assertRewardBucketsEqual(Ledger.RewardBucket expected,
-            Ledger.RewardBucket actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        assertEquals(expected.startTimeMs, actual.startTimeMs);
-        assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
-    }
-
-    private void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
-        if (expected == null) {
-            assertNull(actual);
-            return;
-        }
-        assertNotNull(actual);
-        assertEquals(expected.startTimeMs, actual.startTimeMs);
-        assertEquals(expected.endTimeMs, actual.endTimeMs);
-        assertEquals(expected.eventId, actual.eventId);
-        assertEquals(expected.tag, actual.tag);
-        assertEquals(expected.delta, actual.delta);
-        assertEquals(expected.ctp, actual.ctp);
-    }
-
     private void addInstalledPackage(int userId, String pkgName) {
         PackageInfo pkgInfo = new PackageInfo();
         pkgInfo.packageName = pkgName;
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java b/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java
new file mode 100644
index 0000000..1e4684b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.tare;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.util.SparseLongArray;
+
+import java.util.List;
+
+public class TareTestUtils {
+    static void assertLedgersEqual(Ledger expected, Ledger actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
+
+        List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
+        List<Ledger.Transaction> actualTransactions = actual.getTransactions();
+        assertEquals(expectedTransactions.size(), actualTransactions.size());
+        for (int i = 0; i < expectedTransactions.size(); ++i) {
+            assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
+        }
+
+        List<Ledger.RewardBucket> expectedRewardBuckets = expected.getRewardBuckets();
+        List<Ledger.RewardBucket> actualRewardBuckets = actual.getRewardBuckets();
+        assertEquals(expectedRewardBuckets.size(), actualRewardBuckets.size());
+        for (int i = 0; i < expectedRewardBuckets.size(); ++i) {
+            assertRewardBucketsEqual(expectedRewardBuckets.get(i), actualRewardBuckets.get(i));
+        }
+    }
+
+
+    static void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        final int size = expected.size();
+        assertEquals(size, actual.size());
+        for (int i = 0; i < size; ++i) {
+            assertEquals(expected.keyAt(i), actual.keyAt(i));
+            assertEquals(expected.valueAt(i), actual.valueAt(i));
+        }
+    }
+
+    static void assertRewardBucketsEqual(Ledger.RewardBucket expected, Ledger.RewardBucket actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        assertEquals(expected.startTimeMs, actual.startTimeMs);
+        assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
+    }
+
+    static void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
+        if (expected == null) {
+            assertNull(actual);
+            return;
+        }
+        assertNotNull(actual);
+        assertEquals(expected.startTimeMs, actual.startTimeMs);
+        assertEquals(expected.endTimeMs, actual.endTimeMs);
+        assertEquals(expected.eventId, actual.eventId);
+        assertEquals(expected.tag, actual.tag);
+        assertEquals(expected.delta, actual.delta);
+        assertEquals(expected.ctp, actual.ctp);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
index 849e673..00d7541 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
@@ -155,6 +155,27 @@
                 anyInt(), eq(nowElapsed + HOUR_IN_MILLIS), eq(ALARM_TAG), any(), any());
     }
 
+    @Test
+    public void testAddingLargeAlarmTimes() {
+        final AlarmQueue<String> alarmQueue = createAlarmQueue(true, 0);
+        final long nowElapsed = mInjector.getElapsedRealtime();
+
+        InOrder inOrder = inOrder(mAlarmManager);
+
+        alarmQueue.addAlarm("com.android.test.1", Long.MAX_VALUE - 5);
+        inOrder.verify(mAlarmManager, timeout(1000).times(1))
+                .setExact(anyInt(), eq(Long.MAX_VALUE - 5), eq(ALARM_TAG), any(), any());
+        alarmQueue.addAlarm("com.android.test.2", Long.MAX_VALUE - 4);
+        inOrder.verify(mAlarmManager, never())
+                .setExact(anyInt(), anyLong(), eq(ALARM_TAG), any(), any());
+        alarmQueue.addAlarm("com.android.test.3", nowElapsed + 5);
+        inOrder.verify(mAlarmManager, timeout(1000).times(1))
+                .setExact(anyInt(), eq(nowElapsed + 5), eq(ALARM_TAG), any(), any());
+        alarmQueue.addAlarm("com.android.test.4", nowElapsed + 6);
+        inOrder.verify(mAlarmManager, never())
+                .setExact(anyInt(), anyLong(), eq(ALARM_TAG), any(), any());
+    }
+
     /**
      * Verify that updating the alarm time for a key will result in the AlarmManager alarm changing,
      * if needed.
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
index 3e8cef9..ae25c1b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
@@ -103,6 +103,24 @@
     }
 
     @Test
+    public void testV_msgFormattedWithException_enabled() {
+        enableLogging(Log.VERBOSE);
+
+        Slogf.v(TAG, mException, "msg in a %s", "bottle");
+
+        verify(()-> Slog.v(TAG, "msg in a bottle", mException));
+    }
+
+    @Test
+    public void testV_msgFormattedWithException_disabled() {
+        disableLogging(Log.VERBOSE);
+
+        Slogf.v(TAG, "msg in a %s", "bottle");
+
+        verify(()-> Slog.v(eq(TAG), any(String.class), any(Throwable.class)), never());
+    }
+
+    @Test
     public void testD_msg() {
         Slogf.d(TAG, "msg");
 
@@ -135,6 +153,24 @@
     }
 
     @Test
+    public void testD_msgFormattedWithException_enabled() {
+        enableLogging(Log.DEBUG);
+
+        Slogf.d(TAG, mException, "msg in a %s", "bottle");
+
+        verify(()-> Slog.d(TAG, "msg in a bottle", mException));
+    }
+
+    @Test
+    public void testD_msgFormattedWithException_disabled() {
+        disableLogging(Log.DEBUG);
+
+        Slogf.d(TAG, mException, "msg in a %s", "bottle");
+
+        verify(()-> Slog.d(eq(TAG), any(String.class), any(Throwable.class)), never());
+    }
+
+    @Test
     public void testI_msg() {
         Slogf.i(TAG, "msg");
 
@@ -167,6 +203,24 @@
     }
 
     @Test
+    public void testI_msgFormattedWithException_enabled() {
+        enableLogging(Log.INFO);
+
+        Slogf.i(TAG, mException, "msg in a %s", "bottle");
+
+        verify(()-> Slog.i(TAG, "msg in a bottle", mException));
+    }
+
+    @Test
+    public void testI_msgFormattedWithException_disabled() {
+        disableLogging(Log.INFO);
+
+        Slogf.i(TAG, mException, "msg in a %s", "bottle");
+
+        verify(()-> Slog.i(eq(TAG), any(String.class), any(Throwable.class)), never());
+    }
+
+    @Test
     public void testW_msg() {
         Slogf.w(TAG, "msg");
 
@@ -218,7 +272,7 @@
     public void testW_msgFormattedWithException_disabled() {
         disableLogging(Log.WARN);
 
-        Slogf.w(TAG, "msg in a %s", "bottle");
+        Slogf.w(TAG, mException, "msg in a %s", "bottle");
 
         verify(()-> Slog.w(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -268,7 +322,7 @@
     public void testE_msgFormattedWithException_disabled() {
         disableLogging(Log.ERROR);
 
-        Slogf.e(TAG, "msg in a %s", "bottle");
+        Slogf.e(TAG, mException, "msg in a %s", "bottle");
 
         verify(()-> Slog.e(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index c7757f7..acbcad5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.accessibility;
 
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
 import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
 import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
 
@@ -587,10 +588,12 @@
         verify(mMockA11yEventSender, times(2))
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
-                allOf(a11yWindowId(currentActiveWindowId),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
         assertThat(captor.getAllValues().get(1),
-                allOf(a11yWindowId(eventWindowId),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
     }
 
@@ -600,7 +603,7 @@
                 DEFAULT_FOCUSED_INDEX);
         final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
                 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
-        assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
+        assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
 
         final int noUse = 0;
         mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
@@ -612,14 +615,65 @@
                 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
         final ArgumentCaptor<AccessibilityEvent> captor =
                 ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
+            throws RemoteException {
+        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+                Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
+            throws RemoteException {
+        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+                SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
+    }
+
+    private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+            int initialDisplayId, int eventDisplayId) throws RemoteException {
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
+                initialDisplayId, DEFAULT_FOCUSED_INDEX);
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                initialWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
+        Mockito.reset(mMockA11yEventSender);
+
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
+                eventDisplayId, DEFAULT_FOCUSED_INDEX);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
         verify(mMockA11yEventSender, times(2))
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
-                allOf(a11yWindowId(currentA11yFocusedWindowId),
+                allOf(displayId(initialDisplayId),
+                        a11yWindowId(initialWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
         assertThat(captor.getAllValues().get(1),
-                allOf(a11yWindowId(eventWindowId),
+                allOf(displayId(eventDisplayId),
+                        a11yWindowId(eventWindowId),
                         a11yWindowChanges(
                                 AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
     }
@@ -674,10 +728,12 @@
         verify(mMockA11yEventSender, times(2))
                 .sendAccessibilityEventForCurrentUserLocked(captor.capture());
         assertThat(captor.getAllValues().get(0),
-                allOf(a11yWindowId(eventWindowId),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
         assertThat(captor.getAllValues().get(1),
-                allOf(a11yWindowId(currentActiveWindowId),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
                         a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
     }
 
@@ -861,6 +917,77 @@
         assertTrue(TextUtils.equals(layoutParams.accessibilityTitle, a11yWindow.getTitle()));
     }
 
+    @Test
+    public void sendAccessibilityEventOnWindowRemoval() {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+        // Removing index 0 because it's not focused, and avoids unnecessary layer change.
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        infos.remove(0);
+        for (WindowInfo info : infos) {
+            // Adjust layer number because it should start from 0.
+            info.layer--;
+        }
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+        for (WindowInfo info : infos) {
+            // Adjust layer number because new window will have 0 so that layer number in
+            // A11yWindowInfo in window won't be changed.
+            info.layer++;
+        }
+
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, USER_SYSTEM_ID);
+        addWindowInfo(infos, token, 0);
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowChange() {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+        infos.get(0).title = "new title";
+        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
+    }
+
     private void registerLeashedTokenAndWindowId() {
         mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
         mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
@@ -1018,6 +1145,29 @@
         }
     }
 
+    static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private final int mDisplayId;
+
+        DisplayIdMatcher(int displayId) {
+            super();
+            mDisplayId = displayId;
+        }
+
+        static DisplayIdMatcher displayId(int displayId) {
+            return new DisplayIdMatcher(displayId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getDisplayId() == mDisplayId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to displayId " + mDisplayId);
+        }
+    }
+
     static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
         private int mWindowId;
 
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index db12092..81f899c 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -48,6 +48,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
@@ -64,7 +65,6 @@
 import static org.mockito.Mockito.validateMockitoUsage;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
 
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -90,6 +90,7 @@
 import android.os.storage.IStorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.util.Log;
+import android.view.Display;
 
 import androidx.test.filters.SmallTest;
 
@@ -177,10 +178,16 @@
             doNothing().when(mInjector).activityManagerOnUserStopped(anyInt());
             doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
             doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt());
+            mockIsUsersOnSecondaryDisplaysEnabled(false);
             // All UserController params are set to default.
             mUserController = new UserController(mInjector);
+
+            // TODO(b/232452368): need to explicitly call setAllowUserUnlocking(), otherwise most
+            // tests would fail. But we might need to disable it for the onBootComplete() test (i.e,
+            // to make sure the users are unlocked at the right time)
+            mUserController.setAllowUserUnlocking(true);
             setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
-            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true, null);
+            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated= */ true, null);
         });
     }
 
@@ -199,11 +206,37 @@
         verify(mInjector.getWindowManager()).setSwitchingUser(true);
         verify(mInjector).clearAllLockedTasks(anyString());
         startForegroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
     }
 
     @Test
     public void testStartUser_background() {
-        mUserController.startUser(TEST_USER_ID, false /* foreground */);
+        boolean started = mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+        assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
+        verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+        verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
+        verify(mInjector, never()).clearAllLockedTasks(anyString());
+        startBackgroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testStartUserOnSecondaryDisplay_defaultDisplay() {
+        assertThrows(IllegalArgumentException.class, () -> mUserController
+                .startUserOnSecondaryDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY));
+
+        verifyUserNeverAssignedToDisplay();
+    }
+
+    @Test
+    public void testStartUserOnSecondaryDisplay() {
+        boolean started = mUserController.startUserOnSecondaryDisplay(TEST_USER_ID, 42);
+
+        assertWithMessage("startUserOnSecondaryDisplay(%s, %s)", TEST_USER_ID, 42).that(started)
+                .isTrue();
+        verifyUserAssignedToDisplay(TEST_USER_ID, 42);
+
+        // TODO(b/239982558): might need to change assertions
         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
         verify(mInjector, never()).clearAllLockedTasks(anyString());
@@ -600,6 +633,16 @@
     }
 
     @Test
+    public void testUserNotUnlockedBeforeAllowed() throws Exception {
+        mUserController.setAllowUserUnlocking(false);
+
+        mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
+
+        verify(mInjector.mStorageManagerMock, never())
+                .unlockUserKey(eq(TEST_USER_ID), anyInt(), any());
+    }
+
+    @Test
     public void testStartProfile_fullUserFails() {
         setUpUser(TEST_USER_ID1, 0);
         assertThrows(IllegalArgumentException.class,
@@ -611,6 +654,7 @@
         setUpAndStartUserInBackground(TEST_USER_ID1);
         assertThrows(IllegalArgumentException.class,
                 () -> mUserController.stopProfile(TEST_USER_ID1));
+        verifyUserUnassignedFromDisplayNeverCalled(TEST_USER_ID);
     }
 
     @Test
@@ -623,13 +667,26 @@
     @Test
     public void testStartProfile() throws Exception {
         setUpAndStartProfileInBackground(TEST_USER_ID1);
+
         startBackgroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID1, Display.DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testStartProfile_whenUsersOnSecondaryDisplaysIsEnabled() throws Exception {
+        mockIsUsersOnSecondaryDisplaysEnabled(true);
+
+        setUpAndStartProfileInBackground(TEST_USER_ID1);
+
+        startBackgroundUserAssertions();
+        verifyUserAssignedToDisplay(TEST_USER_ID1, UserManagerInternal.PARENT_DISPLAY);
     }
 
     @Test
     public void testStopProfile() throws Exception {
         setUpAndStartProfileInBackground(TEST_USER_ID1);
         assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
+        verifyUserUnassignedFromDisplay(TEST_USER_ID1);
     }
 
     /** Tests handleIncomingUser() for a variety of permissions and situations. */
@@ -680,7 +737,7 @@
                 eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(false);
 
         checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, true);
-        checkHandleIncomingUser(user1a.id, user2.id,  ALLOW_NON_FULL_IN_PROFILE, false);
+        checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, false);
         checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, false);
         checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, true);
 
@@ -876,6 +933,26 @@
         }
     }
 
+    private void mockIsUsersOnSecondaryDisplaysEnabled(boolean value) {
+        when(mInjector.isUsersOnSecondaryDisplaysEnabled()).thenReturn(value);
+    }
+
+    private void verifyUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
+        verify(mInjector.getUserManagerInternal()).assignUserToDisplay(userId, displayId);
+    }
+
+    private void verifyUserNeverAssignedToDisplay() {
+        verify(mInjector.getUserManagerInternal(), never()).assignUserToDisplay(anyInt(), anyInt());
+    }
+
+    private void verifyUserUnassignedFromDisplay(@UserIdInt int userId) {
+        verify(mInjector.getUserManagerInternal()).unassignUserFromDisplay(userId);
+    }
+
+    private void verifyUserUnassignedFromDisplayNeverCalled(@UserIdInt int userId) {
+        verify(mInjector.getUserManagerInternal(), never()).unassignUserFromDisplay(userId);
+    }
+
     // Should be public to allow mocking
     private static class TestInjector extends UserController.Injector {
         public final TestHandler mHandler;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 92e1f27a..837b553 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.biometrics.sensors.fingerprint.aidl;
 
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -253,6 +255,16 @@
         showHideOverlay(c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
     }
 
+    @Test
+    public void testPowerPressForwardsAcquireMessage() throws RemoteException {
+        final FingerprintEnrollClient client = createClient();
+        client.start(mCallback);
+        client.onPowerPressed();
+
+        verify(mClientMonitorCallbackConverter).onAcquired(anyInt(),
+                eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt());
+    }
+
     private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
             throws RemoteException {
         final FingerprintEnrollClient client = createClient();
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
index b7f5640..cc5ed92 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
@@ -25,7 +25,6 @@
 
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
-import android.hardware.input.InputDeviceCountryCode;
 import android.hardware.input.InputManager;
 import android.os.RemoteException;
 import android.testing.TestableLooper;
@@ -81,11 +80,16 @@
     private Void handleNativeOpenInputDevice(InvocationOnMock inv) {
         Objects.requireNonNull(mDevicesChangedListener,
                 "InputController did not register an InputDevicesChangedListener.");
-        // We only use a subset of the fields of InputDevice in InputController.
-        final InputDevice device = new InputDevice(mDevices.size() /*id*/, 1 /*generation*/, 0,
-                inv.getArgument(0) /*name*/, inv.getArgument(1) /*vendorId*/,
-                inv.getArgument(2) /*productId*/, inv.getArgument(3) /*descriptor*/, true, 0, 0,
-                null, InputDeviceCountryCode.INVALID, false, false, false, false, false);
+
+        final InputDevice device = new InputDevice.Builder()
+                .setId(mDevices.size())
+                .setName(inv.getArgument(0))
+                .setVendorId(inv.getArgument(1))
+                .setProductId(inv.getArgument(2))
+                .setDescriptor(inv.getArgument(3))
+                .setExternal(true)
+                .build();
+
         mDevices.add(device);
         try {
             mDevicesChangedListener.onInputDevicesChanged(
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index eda9133..171b895 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -402,7 +402,7 @@
             // PO needs to be a DA.
             dpm.setActiveAdmin(admin, /*replace=*/ false);
             // Fire!
-            assertThat(dpm.setProfileOwner(admin, "owner-name", CALLER_USER_HANDLE)).isTrue();
+            assertThat(dpm.setProfileOwner(admin, CALLER_USER_HANDLE)).isTrue();
             // Check
             assertThat(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)).isEqualTo(admin);
         });
@@ -966,7 +966,7 @@
 
         // Set admin1 to active admin and device owner
         dpm.setActiveAdmin(admin1, false);
-        dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM);
+        dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM);
 
         // Save password history length
         dpm.setPasswordHistoryLength(admin1, passwordHistoryLength);
@@ -1074,7 +1074,7 @@
         dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
         assertExpectException(IllegalStateException.class,
                 /* messageRegex= */ "already has a device owner",
-                () -> dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM));
+                () -> dpm.setProfileOwner(admin2, UserHandle.USER_SYSTEM));
 
         // DO admin can't be deactivated.
         dpm.removeActiveAdmin(admin1);
@@ -1098,7 +1098,7 @@
         dpm.setActiveAdmin(admin2, /* refreshing= */ true, CALLER_USER_HANDLE);
         assertExpectException(IllegalStateException.class,
                 /* messageRegex= */ "profile owner is already set",
-                () -> dpm.setProfileOwner(admin2, "owner-name", CALLER_USER_HANDLE));
+                () -> dpm.setProfileOwner(admin2, CALLER_USER_HANDLE));
 
         // DO admin can't be deactivated.
         dpm.removeActiveAdmin(admin1);
@@ -1124,7 +1124,7 @@
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
 
         // Fire!
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         // getDeviceOwnerComponent should return the admin1 component.
         assertThat(dpm.getDeviceOwnerComponentOnCallingUser()).isEqualTo(admin1);
@@ -1181,7 +1181,7 @@
             // DO needs to be a DA
             dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
             // DO should be set on headless system user
-            assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+            assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
             // PO should be set on calling user.
             assertThat(dpm.getProfileOwnerAsUser(CALLER_USER_HANDLE)).isEqualTo(admin1);
         });
@@ -1353,7 +1353,7 @@
 
         assertExpectException(IllegalArgumentException.class,
                 /* messageRegex= */ "Invalid component",
-                () -> dpm.setDeviceOwner(new ComponentName("a.b.c", ".def"), /* ownerName= */ null,
+                () -> dpm.setDeviceOwner(new ComponentName("a.b.c", ".def"),
                         UserHandle.USER_SYSTEM));
     }
 
@@ -1363,13 +1363,13 @@
         // Package doesn't exist and caller is not system
         assertExpectException(SecurityException.class,
                 /* messageRegex= */ "Calling identity is not authorized",
-                () -> dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+                () -> dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM));
 
         // Package exists, but caller is not system
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         assertExpectException(SecurityException.class,
                 /* messageRegex= */ "Calling identity is not authorized",
-                () -> dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+                () -> dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM));
     }
 
     @Test
@@ -1389,7 +1389,7 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
         assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
@@ -1452,7 +1452,7 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
                 eq(UserHandle.USER_SYSTEM), eq(false));
@@ -1493,7 +1493,7 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
         assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
 
         // Now call clear from the secondary user, which should throw.
@@ -1527,7 +1527,7 @@
 
         // Set admin1 to active admin and device owner
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
-        dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM);
+        dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM);
 
         // Add reset password token
         final long handle = 12000;
@@ -1566,8 +1566,7 @@
             dpm.setActiveAdmin(admin2, /* refreshing= */ true, CALLER_USER_HANDLE);
             assertExpectException(IllegalStateException.class,
                     /* messageRegex= */ "already has a profile owner",
-                    () -> dpm.setDeviceOwner(admin2, "owner-name",
-                            CALLER_USER_HANDLE));
+                    () -> dpm.setDeviceOwner(admin2, CALLER_USER_HANDLE));
         });
     }
 
@@ -1604,13 +1603,13 @@
         // Package doesn't exist and caller is not system
         assertExpectException(SecurityException.class,
                 /* messageRegex= */ "Calling identity is not authorized",
-                () -> dpm.setProfileOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+                () -> dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM));
 
         // Package exists, but caller is not system
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         assertExpectException(SecurityException.class,
                 /* messageRegex= */ "Calling identity is not authorized",
-                () -> dpm.setProfileOwner(admin1, "owner-name", UserHandle.USER_SYSTEM));
+                () -> dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM));
     }
 
     @Test
@@ -1656,7 +1655,7 @@
 
         // Set DO on the system user which is only allowed during first boot.
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
-        assertThat(dpm.setDeviceOwner(admin3, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin3, UserHandle.USER_SYSTEM)).isTrue();
         assertThat(dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false)).isEqualTo(admin3);
 
         // Then check getDeviceOwnerAdminLocked().
@@ -1979,8 +1978,7 @@
 
         // Call.
         dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name",
-        UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         assertNoDeviceOwnerRestrictions();
         reset(getServices().userManagerInternal);
@@ -2358,8 +2356,7 @@
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
 
         dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name",
-        UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         assertNoDeviceOwnerRestrictions();
 
@@ -2686,7 +2683,7 @@
                 () -> dpm.getWifiMacAddress(admin1));
 
         // Test 3. Caller has PO, but not DO.
-        assertThat(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
         assertExpectException(SecurityException.class,
                 /* messageRegex= */ INVALID_CALLING_IDENTITY_MSG,
                 () -> dpm.getWifiMacAddress(admin1));
@@ -2695,7 +2692,7 @@
         dpm.clearProfileOwner(admin1);
         dpm.setActiveAdmin(admin1, false);
         // Test 4, Caller is DO now.
-        assertThat(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         // 4-1.  But WifiManager is not ready.
         assertThat(dpm.getWifiMacAddress(admin1)).isNull();
@@ -2738,14 +2735,14 @@
                 INVALID_CALLING_IDENTITY_MSG, () -> dpm.reboot(admin1));
 
         // Set admin1 as PO.
-        assertThat(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
         assertExpectException(SecurityException.class, /* messageRegex= */
                 INVALID_CALLING_IDENTITY_MSG, () -> dpm.reboot(admin1));
 
         // Remove PO and add DO.
         dpm.clearProfileOwner(admin1);
         dpm.setActiveAdmin(admin1, false);
-        assertThat(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         // admin1 is DO.
         // Set current call state of device to ringing.
@@ -3030,7 +3027,7 @@
         // Set a device owner on the system user. Check that the system user becomes affiliated.
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         dpm.setActiveAdmin(admin1, /* replace =*/ false);
-        assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
         assertThat(dpm.isAffiliatedUser()).isTrue();
         assertThat(dpm.getAffiliationIds(admin1).isEmpty()).isTrue();
 
@@ -3234,7 +3231,7 @@
 
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
         dpm.setActiveAdmin(admin1, false);
-        assertThat(dpm.setProfileOwner(admin1, null, CALLER_USER_HANDLE)).isTrue();
+        assertThat(dpm.setProfileOwner(admin1, CALLER_USER_HANDLE)).isTrue();
 
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
@@ -3244,7 +3241,7 @@
 
         setUpPackageManagerForAdmin(admin1, DpmMockContext.SYSTEM_UID);
         dpm.setActiveAdmin(admin1, false);
-        assertThat(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setProfileOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
@@ -3254,7 +3251,7 @@
 
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         dpm.setActiveAdmin(admin1, false);
-        assertThat(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM)).isTrue();
+        assertThat(dpm.setDeviceOwner(admin1, UserHandle.USER_SYSTEM)).isTrue();
 
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
@@ -3767,7 +3764,7 @@
         mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
         setUpPackageManagerForFakeAdmin(admin1, managedProfileAdminUid, admin1);
         dpm.setActiveAdmin(admin1, false, userId);
-        assertThat(dpm.setProfileOwner(admin1, null, userId)).isFalse();
+        assertThat(dpm.setProfileOwner(admin1, userId)).isFalse();
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
 
@@ -8713,7 +8710,7 @@
         setUpPackageManagerForFakeAdmin(admin, adminUid, /* enabledSetting= */ null,
                 appTargetSdk, copyFromAdmin);
         dpm.setActiveAdmin(admin, false, userId);
-        assertThat(dpm.setProfileOwner(admin, null, userId)).isTrue();
+        assertThat(dpm.setProfileOwner(admin, userId)).isTrue();
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 9d82f1a..8280fc6 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -82,6 +82,8 @@
     @Mock BrightnessMappingStrategy mIdleBrightnessMappingStrategy;
     @Mock HysteresisLevels mAmbientBrightnessThresholds;
     @Mock HysteresisLevels mScreenBrightnessThresholds;
+    @Mock HysteresisLevels mAmbientBrightnessThresholdsIdle;
+    @Mock HysteresisLevels mScreenBrightnessThresholdsIdle;
     @Mock Handler mNoOpHandler;
     @Mock HighBrightnessModeController mHbmController;
     @Mock BrightnessThrottler mBrightnessThrottler;
@@ -129,6 +131,7 @@
                 INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
                 DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
                 mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
+                mAmbientBrightnessThresholdsIdle, mScreenBrightnessThresholdsIdle,
                 mContext, mHbmController, mBrightnessThrottler, mIdleBrightnessMappingStrategy,
                 AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG
         );
@@ -314,8 +317,9 @@
 
         // Now let's do the same for idle mode
         mController.switchToIdleMode();
-        // Called once for init, and once when switching
-        verify(mBrightnessMappingStrategy, times(2)).isForIdleMode();
+        // Called once for init, and once when switching,
+        // setAmbientLux() is called twice and once in updateAutoBrightness()
+        verify(mBrightnessMappingStrategy, times(5)).isForIdleMode();
         // Ensure, after switching, original BMS is not used anymore
         verifyNoMoreInteractions(mBrightnessMappingStrategy);
 
diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
new file mode 100644
index 0000000..6e422fa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.hardware.BatteryState.STATUS_CHARGING
+import android.hardware.BatteryState.STATUS_FULL
+import android.hardware.input.IInputDeviceBatteryListener
+import android.hardware.input.IInputManager
+import android.hardware.input.InputDeviceCountryCode
+import android.hardware.input.InputManager
+import android.os.Binder
+import android.os.IBinder
+import android.platform.test.annotations.Presubmit
+import android.view.InputDevice
+import androidx.test.InstrumentationRegistry
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.notNull
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+
+/**
+ * Tests for {@link InputDeviceBatteryController}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:InputDeviceBatteryControllerTests
+ */
+@Presubmit
+class BatteryControllerTests {
+    companion object {
+        const val PID = 42
+        const val DEVICE_ID = 13
+        const val SECOND_DEVICE_ID = 11
+    }
+
+    @get:Rule
+    val rule = MockitoJUnit.rule()!!
+
+    @Mock
+    private lateinit var native: NativeInputManagerService
+    @Mock
+    private lateinit var iInputManager: IInputManager
+
+    private lateinit var batteryController: BatteryController
+    private lateinit var context: Context
+
+    @Before
+    fun setup() {
+        context = spy(ContextWrapper(InstrumentationRegistry.getContext()))
+        val inputManager = InputManager.resetInstance(iInputManager)
+        `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager)
+        `when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID, SECOND_DEVICE_ID))
+        `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(createInputDevice(DEVICE_ID))
+        `when`(iInputManager.getInputDevice(SECOND_DEVICE_ID))
+            .thenReturn(createInputDevice(SECOND_DEVICE_ID))
+
+        batteryController = BatteryController(context, native)
+    }
+
+    private fun createInputDevice(deviceId: Int): InputDevice =
+        InputDevice.Builder()
+            .setId(deviceId)
+            .setName("Device $deviceId")
+            .setDescriptor("descriptor $deviceId")
+            .setExternal(true)
+            .setHasBattery(true)
+            .build()
+
+    @After
+    fun tearDown() {
+        InputManager.clearInstance()
+    }
+
+    private fun createMockListener(): IInputDeviceBatteryListener {
+        val listener = mock(IInputDeviceBatteryListener::class.java)
+        val binder = mock(Binder::class.java)
+        `when`(listener.asBinder()).thenReturn(binder)
+        return listener
+    }
+
+    @Test
+    fun testRegisterAndUnregisterBinderLifecycle() {
+        val listener = createMockListener()
+        // Ensure the binder lifecycle is tracked when registering a listener.
+        batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
+        verify(listener.asBinder()).linkToDeath(notNull(), anyInt())
+        batteryController.registerBatteryListener(SECOND_DEVICE_ID, listener, PID)
+        verify(listener.asBinder(), times(1)).linkToDeath(notNull(), anyInt())
+
+        // Ensure the binder lifecycle stops being tracked when all devices stopped being monitored.
+        batteryController.unregisterBatteryListener(SECOND_DEVICE_ID, listener, PID)
+        verify(listener.asBinder(), never()).unlinkToDeath(notNull(), anyInt())
+        batteryController.unregisterBatteryListener(DEVICE_ID, listener, PID)
+        verify(listener.asBinder()).unlinkToDeath(notNull(), anyInt())
+    }
+
+    @Test
+    fun testOneListenerPerProcess() {
+        val listener1 = createMockListener()
+        batteryController.registerBatteryListener(DEVICE_ID, listener1, PID)
+        verify(listener1.asBinder()).linkToDeath(notNull(), anyInt())
+
+        // If a second listener is added for the same process, a security exception is thrown.
+        val listener2 = createMockListener()
+        try {
+            batteryController.registerBatteryListener(DEVICE_ID, listener2, PID)
+            fail("Expected security exception when registering more than one listener per process")
+        } catch (ignored: SecurityException) {
+        }
+    }
+
+    @Test
+    fun testProcessDeathRemovesListener() {
+        val deathRecipient = ArgumentCaptor.forClass(IBinder.DeathRecipient::class.java)
+        val listener = createMockListener()
+        batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
+        verify(listener.asBinder()).linkToDeath(deathRecipient.capture(), anyInt())
+
+        // When the binder dies, the callback is unregistered.
+        deathRecipient.value!!.binderDied(listener.asBinder())
+        verify(listener.asBinder()).unlinkToDeath(notNull(), anyInt())
+
+        // It is now possible to register the same listener again.
+        batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
+        verify(listener.asBinder(), times(2)).linkToDeath(notNull(), anyInt())
+    }
+
+    @Test
+    fun testRegisteringListenerNotifiesStateImmediately() {
+        `when`(native.getBatteryStatus(DEVICE_ID)).thenReturn(STATUS_FULL)
+        `when`(native.getBatteryCapacity(DEVICE_ID)).thenReturn(100)
+        val listener = createMockListener()
+        batteryController.registerBatteryListener(DEVICE_ID, listener, PID)
+        verify(listener).onBatteryStateChanged(eq(DEVICE_ID), eq(true /*isPresent*/),
+            eq(STATUS_FULL), eq(1f), anyLong())
+
+        `when`(native.getBatteryStatus(SECOND_DEVICE_ID)).thenReturn(STATUS_CHARGING)
+        `when`(native.getBatteryCapacity(SECOND_DEVICE_ID)).thenReturn(78)
+        batteryController.registerBatteryListener(SECOND_DEVICE_ID, listener, PID)
+        verify(listener).onBatteryStateChanged(eq(SECOND_DEVICE_ID), eq(true /*isPresent*/),
+            eq(STATUS_CHARGING), eq(0.78f), anyLong())
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ConcurrentLinkedEvictingDequeTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ConcurrentLinkedEvictingDequeTest.java
new file mode 100644
index 0000000..9169a0d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ConcurrentLinkedEvictingDequeTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.contexthub;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class ConcurrentLinkedEvictingDequeTest {
+    @Test
+    public void testMaxSize() {
+        int maxSize = 20;
+        ConcurrentLinkedEvictingDeque<Integer> deque =
+                new ConcurrentLinkedEvictingDeque<Integer>(maxSize);
+
+        // add items to the queue
+        for (int i = 0; i < maxSize; i++) {
+            deque.add(i);
+        }
+
+        // test the max size
+        deque.add(maxSize);
+        assertThat(deque.peek() == 0).isFalse();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java
new file mode 100644
index 0000000..8863d27
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEventLoggerTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.contexthub;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.location.NanoAppMessage;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class ContextHubEventLoggerTest {
+    private static final ContextHubEventLogger sInstance = ContextHubEventLogger.getInstance();
+
+    @Test
+    public void testLogNanoappLoad() {
+        ContextHubEventLogger.NanoappLoadEvent[] events =
+                new ContextHubEventLogger.NanoappLoadEvent[] {
+                    new ContextHubEventLogger.NanoappLoadEvent(0, -1, 42, -34, 100, false),
+                    new ContextHubEventLogger.NanoappLoadEvent(0, 0, 123, 321, 001, true)
+                };
+        String[] eventStrings = generateEventDumpStrings(events);
+
+        // log events and test sInstance.toString() contains event details
+        sInstance.clear();
+        sInstance.logNanoappLoad(-1, 42, -34, 100, false);
+        sInstance.logNanoappLoad(0, 123, 321, 001, true);
+        String sInstanceDump = sInstance.toString();
+        for (String eventString: eventStrings) {
+            assertThat(eventString.length() > 0).isTrue();
+            assertThat(sInstanceDump.contains(eventString)).isTrue();
+        }
+    }
+
+    @Test
+    public void testLogNanoappUnload() {
+        ContextHubEventLogger.NanoappUnloadEvent[] events =
+                new ContextHubEventLogger.NanoappUnloadEvent[] {
+                    new ContextHubEventLogger.NanoappUnloadEvent(0, -1, 47, false),
+                    new ContextHubEventLogger.NanoappUnloadEvent(0, 1, 0xFFFFFFFF, true)
+                };
+        String[] eventStrings = generateEventDumpStrings(events);
+
+        // log events and test sInstance.toString() contains event details
+        sInstance.clear();
+        sInstance.logNanoappUnload(-1, 47, false);
+        sInstance.logNanoappUnload(1, 0xFFFFFFFF, true);
+        String sInstanceDump = sInstance.toString();
+        for (String eventString: eventStrings) {
+            assertThat(eventString.length() > 0).isTrue();
+            assertThat(sInstanceDump.contains(eventString)).isTrue();
+        }
+    }
+
+    @Test
+    public void testLogMessageFromNanoapp() {
+        NanoAppMessage message1 = NanoAppMessage.createMessageFromNanoApp(1, 0,
+                new byte[] {0x00, 0x11, 0x22, 0x33}, false);
+        NanoAppMessage message2 = NanoAppMessage.createMessageFromNanoApp(0, 1,
+                new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF}, true);
+        ContextHubEventLogger.NanoappMessageEvent[] events =
+                new ContextHubEventLogger.NanoappMessageEvent[] {
+                    new ContextHubEventLogger.NanoappMessageEvent(8, -123, message1, false),
+                    new ContextHubEventLogger.NanoappMessageEvent(9, 321, message2, true)
+                };
+        String[] eventStrings = generateEventDumpStrings(events);
+
+        // log events and test sInstance.toString() contains event details
+        sInstance.clear();
+        sInstance.logMessageFromNanoapp(-123, message1, false);
+        sInstance.logMessageFromNanoapp(321, message2, true);
+        String sInstanceDump = sInstance.toString();
+        for (String eventString: eventStrings) {
+            assertThat(eventString.length() > 0).isTrue();
+            assertThat(sInstanceDump.contains(eventString)).isTrue();
+        }
+    }
+
+    @Test
+    public void testLogMessageToNanoapp() {
+        NanoAppMessage message1 = NanoAppMessage.createMessageToNanoApp(1, 0,
+                new byte[] {0x00, 0x11, 0x22, 0x33});
+        NanoAppMessage message2 = NanoAppMessage.createMessageToNanoApp(0, 1,
+                new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
+        ContextHubEventLogger.NanoappMessageEvent[] events =
+                new ContextHubEventLogger.NanoappMessageEvent[] {
+                    new ContextHubEventLogger.NanoappMessageEvent(23, 888, message1, true),
+                    new ContextHubEventLogger.NanoappMessageEvent(34, 999, message2, false)
+                };
+        String[] eventStrings = generateEventDumpStrings(events);
+
+        // log events and test sInstance.toString() contains event details
+        sInstance.clear();
+        sInstance.logMessageToNanoapp(888, message1, true);
+        sInstance.logMessageToNanoapp(999, message2, false);
+        String sInstanceDump = sInstance.toString();
+        for (String eventString: eventStrings) {
+            assertThat(eventString.length() > 0).isTrue();
+            assertThat(sInstanceDump.contains(eventString)).isTrue();
+        }
+    }
+
+    @Test
+    public void testLogContextHubRestart() {
+        ContextHubEventLogger.ContextHubRestartEvent[] events =
+                new ContextHubEventLogger.ContextHubRestartEvent[] {
+                    new ContextHubEventLogger.ContextHubRestartEvent(0, 1),
+                    new ContextHubEventLogger.ContextHubRestartEvent(1, 2)
+                };
+        String[] eventStrings = generateEventDumpStrings(events);
+
+        // log events and test sInstance.toString() contains event details
+        sInstance.clear();
+        sInstance.logContextHubRestart(1);
+        sInstance.logContextHubRestart(2);
+        String sInstanceDump = sInstance.toString();
+        for (String eventString: eventStrings) {
+            assertThat(eventString.length() > 0).isTrue();
+            assertThat(sInstanceDump.contains(eventString)).isTrue();
+        }
+    }
+
+    /**
+     * Generates the part of the event's toString() method that should be contained in the dump
+     * output (everything without the timestamp).
+     *
+     * @param events        the events
+     * @return              the string representation of the events
+     */
+    private String[] generateEventDumpStrings(ContextHubEventLogger.ContextHubEventBase[] events) {
+        return (String[]) Arrays.stream(events)
+                .map(event -> event.toString().split(event.getClass().getSimpleName(), 2)[1])
+                .toArray(String[]::new);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 821ce5e..3bcde6a 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -168,13 +168,13 @@
 import com.android.internal.util.test.FsUtil;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppStandbyInternal;
 
-import com.google.common.util.concurrent.AbstractFuture;
-
 import libcore.io.Streams;
 
+import com.google.common.util.concurrent.AbstractFuture;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index 38125c7..8f6dd5d 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -23,7 +23,7 @@
 import android.os.Process
 import android.util.ArrayMap
 import com.android.server.om.OverlayActorEnforcer.ActorState
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
 import com.google.common.truth.Truth.assertThat
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index b793482..301697d 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -33,13 +33,11 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
 
 import androidx.annotation.Nullable;
 
 import com.android.internal.content.om.OverlayConfig;
-import com.android.internal.util.CollectionUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index 876c845..7be4921 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -17,7 +17,7 @@
 package com.android.server.om
 
 import android.net.Uri
-import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.pkg.AndroidPackage
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
 import com.google.common.truth.Truth.assertThat
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 66c3f07..050fbea 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -93,7 +93,7 @@
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationManagerInternal;
 import com.android.server.people.PeopleService;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import com.google.common.collect.Iterables;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 503ca69..a7739ed 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -47,7 +47,7 @@
 
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
index af3b52f..c321639 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java
@@ -47,9 +47,9 @@
 import androidx.annotation.NonNull;
 
 import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedActivityImpl;
 import com.android.server.pm.pkg.component.ParsedComponentImpl;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b32ace5..67eeb4e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -62,11 +62,11 @@
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.CompatibilityPermissionInfo;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.component.ParsedActivity;
 import com.android.server.pm.pkg.component.ParsedActivityImpl;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 94d8358..42be3d3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -19,7 +19,8 @@
 import android.content.pm.SigningDetails;
 import android.util.SparseArray;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageUserStateImpl;
 
 import java.io.File;
@@ -166,7 +167,7 @@
         packageSetting.setSignatures(mSigningDetails != null
                 ? new PackageSignatures(mSigningDetails)
                 : new PackageSignatures());
-        packageSetting.setPkg(mPkg);
+        packageSetting.setPkg((ParsedPackage) mPkg);
         packageSetting.setAppId(mAppId);
         packageSetting.setVolumeUuid(this.mVolumeUuid);
         if (mInstallSource != null) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index 901b200..eb91671 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -26,9 +26,9 @@
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 9962a3c..1c3673e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -20,8 +20,8 @@
 import android.annotation.Nullable;
 import android.os.UserHandle;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 class ScanRequestBuilder {
     private final ParsedPackage mPkg;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 8e53ca1..084f4f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -43,8 +43,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.SharedLibraryInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
 import android.content.res.TypedArray;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -53,9 +51,11 @@
 
 import com.android.server.compat.PlatformCompat;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
 
 import org.hamcrest.BaseMatcher;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index ba7a103..b7729bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -55,9 +55,9 @@
 
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index b7b55ba..b2843d8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -39,9 +39,9 @@
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.PackageManagerException;
 import com.android.server.pm.parsing.TestPackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 7c8bbec..ad9f920 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -23,16 +23,16 @@
 import static org.junit.Assert.fail;
 
 import android.content.pm.SharedLibraryInfo;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
 
 import dalvik.system.DelegateLastClassLoader;
 import dalvik.system.DexClassLoader;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index f013ecc..9cd97ff3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -46,14 +46,13 @@
 import com.android.frameworks.servicestests.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.PackageManagerException;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.component.ParsedActivityUtils;
 import com.android.server.pm.pkg.component.ParsedComponent;
 import com.android.server.pm.pkg.component.ParsedIntentInfo;
 import com.android.server.pm.pkg.component.ParsedPermission;
 import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackage;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 
 import com.google.common.truth.Expect;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 6b60042..d3107b0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -24,9 +24,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
index 70d85b6..36308d2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -21,9 +21,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index f536052..3782f5d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -23,9 +23,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index 77197e3..a739607 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -25,9 +25,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
index 0b144dc..3977d0d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
@@ -23,9 +23,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
index 404f29c..a31c781 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
@@ -21,9 +21,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index 95b8d3f..f5e3f4e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -23,9 +23,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index b28446b..b3648b1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -23,16 +23,16 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.android.server.pm.pkg.parsing.ParsingPackage;
 import android.os.Build;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
 
 import org.junit.Assume;
 import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
index a71572f..2450a14 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -18,8 +18,8 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.util.function.Supplier;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index 1122490..2825c69 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -24,9 +24,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index 3cc8475..c0da8a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -24,9 +24,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
index fd40880..cff3bf8 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
@@ -38,6 +38,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -78,6 +79,7 @@
         batteryOnScreenOff();
     }
 
+    @Ignore("b/244349060")
     @Test
     public void testNoCpuDataForRemovedUser() throws Exception {
         mIam.startUserInBackground(mTestUserId);
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
index 6402e12..3f550d0 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
@@ -16,15 +16,18 @@
 
 package com.android.server.timedetector;
 
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
 import android.content.Context;
 import android.location.Location;
 import android.location.LocationListener;
@@ -36,9 +39,6 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.server.LocalServices;
-
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -64,19 +64,13 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
-                .thenReturn(true);
+        installGpsProviderInMockLocationManager();
 
         mGnssTimeUpdateService = new GnssTimeUpdateService(
                 mMockContext, mMockAlarmManager, mMockLocationManager, mMockLocationManagerInternal,
                 mMockTimeDetectorInternal);
     }
 
-    @After
-    public void tearDown() {
-        LocalServices.removeServiceForTest(LocationManagerInternal.class);
-    }
-
     @Test
     public void testLocationListenerOnLocationChanged_validLocationTime_suggestsGnssTime() {
         TimestampedValue<Long> timeSignal = new TimestampedValue<>(
@@ -85,9 +79,9 @@
         LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
         doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
 
-        mGnssTimeUpdateService.requestGnssTimeUpdates();
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
 
-        ArgumentCaptor<LocationListener> argumentCaptor =
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
                 ArgumentCaptor.forClass(LocationListener.class);
         verify(mMockLocationManager).requestLocationUpdates(
                 eq(LocationManager.GPS_PROVIDER),
@@ -95,8 +89,8 @@
                     .setMinUpdateIntervalMillis(0)
                     .build()),
                 any(),
-                argumentCaptor.capture());
-        LocationListener locationListener = argumentCaptor.getValue();
+                locationListenerCaptor.capture());
+        LocationListener locationListener = locationListenerCaptor.getValue();
         Location location = new Location(LocationManager.GPS_PROVIDER);
 
         locationListener.onLocationChanged(location);
@@ -115,9 +109,9 @@
     public void testLocationListenerOnLocationChanged_nullLocationTime_doesNotSuggestGnssTime() {
         doReturn(null).when(mMockLocationManagerInternal).getGnssTimeMillis();
 
-        mGnssTimeUpdateService.requestGnssTimeUpdates();
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
 
-        ArgumentCaptor<LocationListener> argumentCaptor =
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
                 ArgumentCaptor.forClass(LocationListener.class);
         verify(mMockLocationManager).requestLocationUpdates(
                 eq(LocationManager.GPS_PROVIDER),
@@ -125,14 +119,14 @@
                     .setMinUpdateIntervalMillis(0)
                     .build()),
                 any(),
-                argumentCaptor.capture());
-        LocationListener locationListener = argumentCaptor.getValue();
+                locationListenerCaptor.capture());
+        LocationListener locationListener = locationListenerCaptor.getValue();
         Location location = new Location(LocationManager.GPS_PROVIDER);
 
         locationListener.onLocationChanged(location);
 
         verify(mMockLocationManager).removeUpdates(locationListener);
-        verify(mMockTimeDetectorInternal, never()).suggestGnssTime(any());
+        verifyZeroInteractions(mMockTimeDetectorInternal);
         verify(mMockAlarmManager).set(
                 eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
                 anyLong(),
@@ -140,4 +134,90 @@
                 any(),
                 any());
     }
+
+    @Test
+    public void testLocationListeningRestartsAfterSleep() {
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
+                ArgumentCaptor.forClass(LocationListener.class);
+        ArgumentCaptor<OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(OnAlarmListener.class);
+
+        advanceServiceToSleepingState(locationListenerCaptor, alarmListenerCaptor);
+
+        // Simulate the alarm manager's wake-up call.
+        OnAlarmListener wakeUpListener = alarmListenerCaptor.getValue();
+        wakeUpListener.onAlarm();
+
+        // Verify the service returned to location listening.
+        verify(mMockLocationManager).requestLocationUpdates(any(), any(), any(), any());
+        verifyZeroInteractions(mMockAlarmManager, mMockTimeDetectorInternal);
+    }
+
+    // Tests what happens when a call is made to startGnssListeningInternal() when service is
+    // sleeping. This can happen when the start_gnss_listening shell command is used.
+    @Test
+    public void testStartGnssListeningInternalCalledWhenSleeping() {
+        ArgumentCaptor<LocationListener> locationListenerCaptor =
+                ArgumentCaptor.forClass(LocationListener.class);
+        ArgumentCaptor<OnAlarmListener> alarmListenerCaptor =
+                ArgumentCaptor.forClass(OnAlarmListener.class);
+
+        advanceServiceToSleepingState(locationListenerCaptor, alarmListenerCaptor);
+
+        // Call startGnssListeningInternal(), as can happen if the start_gnss_listening shell
+        // command is used.
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
+
+        // Verify the alarm manager is told to stopped sleeping and the location manager is
+        // listening again.
+        verify(mMockAlarmManager).cancel(alarmListenerCaptor.getValue());
+        verify(mMockLocationManager).requestLocationUpdates(any(), any(), any(), any());
+        verifyZeroInteractions(mMockTimeDetectorInternal);
+    }
+
+    private void advanceServiceToSleepingState(
+            ArgumentCaptor<LocationListener> locationListenerCaptor,
+            ArgumentCaptor<OnAlarmListener> alarmListenerCaptor) {
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(
+                ELAPSED_REALTIME_MS, GNSS_TIME);
+        GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
+        LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
+        doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
+
+        assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
+
+        verify(mMockLocationManager).requestLocationUpdates(
+                any(), any(), any(), locationListenerCaptor.capture());
+        LocationListener locationListener = locationListenerCaptor.getValue();
+        Location location = new Location(LocationManager.GPS_PROVIDER);
+        verifyZeroInteractions(mMockAlarmManager, mMockTimeDetectorInternal);
+
+        locationListener.onLocationChanged(location);
+
+        verify(mMockLocationManager).removeUpdates(locationListener);
+        verify(mMockTimeDetectorInternal).suggestGnssTime(timeSuggestion);
+
+        // Verify the service is now "sleeping", i.e. waiting for a period before listening for
+        // GNSS locations again.
+        verify(mMockAlarmManager).set(
+                eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+                anyLong(),
+                any(),
+                alarmListenerCaptor.capture(),
+                any());
+
+        // Reset mocks making it easier to verify the calls that follow.
+        reset(mMockAlarmManager, mMockTimeDetectorInternal, mMockLocationManager,
+                mMockLocationManagerInternal);
+        installGpsProviderInMockLocationManager();
+    }
+
+    /**
+     * Configures the mock response to ensure {@code
+     * locationManager.hasProvider(LocationManager.GPS_PROVIDER) == true }
+     */
+    private void installGpsProviderInMockLocationManager() {
+        when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
+                .thenReturn(true);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index ec4ad89..2ac8b37 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -33,7 +33,6 @@
 import android.content.ContextWrapper;
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
-import android.hardware.input.InputDeviceCountryCode;
 import android.hardware.input.InputManager;
 import android.os.CombinedVibration;
 import android.os.Handler;
@@ -328,10 +327,11 @@
     }
 
     private InputDevice createInputDevice(int id, boolean hasVibrator) {
-        return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
-                null, InputDeviceCountryCode.INVALID, hasVibrator, false, false,
-                false /* hasSensor */, false /* hasBattery */);
-
-
+        return new InputDevice.Builder()
+                .setId(id)
+                .setName("name")
+                .setDescriptor("descriptor")
+                .setHasVibrator(hasVibrator)
+                .build();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
index 99a12c2..508e7b0f 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -161,13 +161,8 @@
             return null;
         }).when(mVirtualDeviceManagerInternalMock).registerAppsOnVirtualDeviceListener(any());
 
-        LocalServices.removeServiceForTest(PowerManagerInternal.class);
-        LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
-        LocalServices.removeServiceForTest(PackageManagerInternal.class);
-        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
-        LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
-        LocalServices.addService(VirtualDeviceManagerInternal.class,
-                mVirtualDeviceManagerInternalMock);
+        removeServicesForTest();
+        addServicesForTest();
 
         setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM);
         mAudioManager = mContextSpy.getSystemService(AudioManager.class);
@@ -185,9 +180,34 @@
         mVibrationSettings.onSystemReady();
     }
 
+    private void removeServicesForTest() {
+        LocalServices.removeServiceForTest(PowerManagerInternal.class);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
+    }
+
+    private void addServicesForTest() {
+        LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
+        LocalServices.addService(VirtualDeviceManagerInternal.class,
+                mVirtualDeviceManagerInternalMock);
+    }
+
     @After
     public void tearDown() throws Exception {
-        LocalServices.removeServiceForTest(PowerManagerInternal.class);
+        removeServicesForTest();
+    }
+
+    @Test
+    public void create_withOnlyRequiredSystemServices() {
+        // The only core services that we depend on are PowerManager and PackageManager
+        removeServicesForTest();
+        LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
+
+        VibrationSettings minimalVibrationSettings = new VibrationSettings(mContextSpy,
+                new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
+        minimalVibrationSettings.onSystemReady();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 8d53b71..c46fecd 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -46,7 +46,6 @@
 import android.content.ContextWrapper;
 import android.content.pm.PackageManagerInternal;
 import android.hardware.input.IInputManager;
-import android.hardware.input.InputDeviceCountryCode;
 import android.hardware.input.InputManager;
 import android.hardware.vibrator.IVibrator;
 import android.hardware.vibrator.IVibratorManager;
@@ -1980,9 +1979,11 @@
     }
 
     private InputDevice createInputDeviceWithVibrator(int id) {
-        return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
-                null, InputDeviceCountryCode.INVALID, /* hasVibrator= */ true, false, false, false,
-                false);
+        return new InputDevice.Builder()
+                .setId(id)
+                .setName("Test Device " + id)
+                .setHasVibrator(true)
+                .build();
     }
 
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 68551d9..1e94577 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -45,19 +45,16 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.pm.VersionedPackage;
 import android.os.Bundle;
-import android.os.IBinder;
-import android.os.IInterface;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerFilter;
 import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationStats;
 import android.service.notification.NotificationRankingUpdate;
+import android.service.notification.NotificationStats;
 import android.service.notification.StatusBarNotification;
 import android.testing.TestableContext;
 import android.util.ArraySet;
@@ -408,64 +405,113 @@
 
     @Test
     public void testNotifyPostedLockedInLockdownMode() {
-        NotificationRecord r = mock(NotificationRecord.class);
-        NotificationRecord old = mock(NotificationRecord.class);
+        NotificationRecord r0 = mock(NotificationRecord.class);
+        NotificationRecord old0 = mock(NotificationRecord.class);
+        UserHandle uh0 = mock(UserHandle.class);
 
-        // before the lockdown mode
-        when(mNm.isInLockDownMode()).thenReturn(false);
-        mListeners.notifyPostedLocked(r, old, true);
-        mListeners.notifyPostedLocked(r, old, false);
-        verify(r, atLeast(2)).getSbn();
+        NotificationRecord r1 = mock(NotificationRecord.class);
+        NotificationRecord old1 = mock(NotificationRecord.class);
+        UserHandle uh1 = mock(UserHandle.class);
 
-        // in the lockdown mode
-        reset(r);
-        reset(old);
-        when(mNm.isInLockDownMode()).thenReturn(true);
-        mListeners.notifyPostedLocked(r, old, true);
-        mListeners.notifyPostedLocked(r, old, false);
-        verify(r, never()).getSbn();
-    }
+        // Neither user0 and user1 is in the lockdown mode
+        when(r0.getUser()).thenReturn(uh0);
+        when(uh0.getIdentifier()).thenReturn(0);
+        when(mNm.isInLockDownMode(0)).thenReturn(false);
 
-    @Test
-    public void testnotifyRankingUpdateLockedInLockdownMode() {
-        List chn = mock(List.class);
+        when(r1.getUser()).thenReturn(uh1);
+        when(uh1.getIdentifier()).thenReturn(1);
+        when(mNm.isInLockDownMode(1)).thenReturn(false);
 
-        // before the lockdown mode
-        when(mNm.isInLockDownMode()).thenReturn(false);
-        mListeners.notifyRankingUpdateLocked(chn);
-        verify(chn, atLeast(1)).size();
+        mListeners.notifyPostedLocked(r0, old0, true);
+        mListeners.notifyPostedLocked(r0, old0, false);
+        verify(r0, atLeast(2)).getSbn();
 
-        // in the lockdown mode
-        reset(chn);
-        when(mNm.isInLockDownMode()).thenReturn(true);
-        mListeners.notifyRankingUpdateLocked(chn);
-        verify(chn, never()).size();
+        mListeners.notifyPostedLocked(r1, old1, true);
+        mListeners.notifyPostedLocked(r1, old1, false);
+        verify(r1, atLeast(2)).getSbn();
+
+        // Reset
+        reset(r0);
+        reset(old0);
+        reset(r1);
+        reset(old1);
+
+        // Only user 0 is in the lockdown mode
+        when(r0.getUser()).thenReturn(uh0);
+        when(uh0.getIdentifier()).thenReturn(0);
+        when(mNm.isInLockDownMode(0)).thenReturn(true);
+
+        when(r1.getUser()).thenReturn(uh1);
+        when(uh1.getIdentifier()).thenReturn(1);
+        when(mNm.isInLockDownMode(1)).thenReturn(false);
+
+        mListeners.notifyPostedLocked(r0, old0, true);
+        mListeners.notifyPostedLocked(r0, old0, false);
+        verify(r0, never()).getSbn();
+
+        mListeners.notifyPostedLocked(r1, old1, true);
+        mListeners.notifyPostedLocked(r1, old1, false);
+        verify(r1, atLeast(2)).getSbn();
     }
 
     @Test
     public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException {
-        NotificationRecord r = mock(NotificationRecord.class);
-        NotificationStats rs = mock(NotificationStats.class);
+        NotificationRecord r0 = mock(NotificationRecord.class);
+        NotificationStats rs0 = mock(NotificationStats.class);
+        UserHandle uh0 = mock(UserHandle.class);
+
+        NotificationRecord r1 = mock(NotificationRecord.class);
+        NotificationStats rs1 = mock(NotificationStats.class);
+        UserHandle uh1 = mock(UserHandle.class);
+
         StatusBarNotification sbn = mock(StatusBarNotification.class);
         FieldSetter.setField(mNm,
                 NotificationManagerService.class.getDeclaredField("mHandler"),
                 mock(NotificationManagerService.WorkerHandler.class));
 
-        // before the lockdown mode
-        when(mNm.isInLockDownMode()).thenReturn(false);
-        when(r.getSbn()).thenReturn(sbn);
-        mListeners.notifyRemovedLocked(r, 0, rs);
-        mListeners.notifyRemovedLocked(r, 0, rs);
-        verify(r, atLeast(2)).getSbn();
+        // Neither user0 and user1 is in the lockdown mode
+        when(r0.getUser()).thenReturn(uh0);
+        when(uh0.getIdentifier()).thenReturn(0);
+        when(mNm.isInLockDownMode(0)).thenReturn(false);
+        when(r0.getSbn()).thenReturn(sbn);
 
-        // in the lockdown mode
-        reset(r);
-        reset(rs);
-        when(mNm.isInLockDownMode()).thenReturn(true);
-        when(r.getSbn()).thenReturn(sbn);
-        mListeners.notifyRemovedLocked(r, 0, rs);
-        mListeners.notifyRemovedLocked(r, 0, rs);
-        verify(r, never()).getSbn();
+        when(r1.getUser()).thenReturn(uh1);
+        when(uh1.getIdentifier()).thenReturn(1);
+        when(mNm.isInLockDownMode(1)).thenReturn(false);
+        when(r1.getSbn()).thenReturn(sbn);
+
+        mListeners.notifyRemovedLocked(r0, 0, rs0);
+        mListeners.notifyRemovedLocked(r0, 0, rs0);
+        verify(r0, atLeast(2)).getSbn();
+
+        mListeners.notifyRemovedLocked(r1, 0, rs1);
+        mListeners.notifyRemovedLocked(r1, 0, rs1);
+        verify(r1, atLeast(2)).getSbn();
+
+        // Reset
+        reset(r0);
+        reset(rs0);
+        reset(r1);
+        reset(rs1);
+
+        // Only user 0 is in the lockdown mode
+        when(r0.getUser()).thenReturn(uh0);
+        when(uh0.getIdentifier()).thenReturn(0);
+        when(mNm.isInLockDownMode(0)).thenReturn(true);
+        when(r0.getSbn()).thenReturn(sbn);
+
+        when(r1.getUser()).thenReturn(uh1);
+        when(uh1.getIdentifier()).thenReturn(1);
+        when(mNm.isInLockDownMode(1)).thenReturn(false);
+        when(r1.getSbn()).thenReturn(sbn);
+
+        mListeners.notifyRemovedLocked(r0, 0, rs0);
+        mListeners.notifyRemovedLocked(r0, 0, rs0);
+        verify(r0, never()).getSbn();
+
+        mListeners.notifyRemovedLocked(r1, 0, rs1);
+        mListeners.notifyRemovedLocked(r1, 0, rs1);
+        verify(r1, atLeast(2)).getSbn();
     }
 
     @Test
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 cae8fd9..92761427 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -174,6 +174,7 @@
 import android.service.notification.ConversationChannelWrapper;
 import android.service.notification.NotificationListenerFilter;
 import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.NotificationStats;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.ZenPolicy;
@@ -9837,10 +9838,10 @@
         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
-        assertTrue(mStrongAuthTracker.isInLockDownMode());
-        mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+        assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
+        mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId());
         mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
-        assertFalse(mStrongAuthTracker.isInLockDownMode());
+        assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId()));
     }
 
     @Test
@@ -9856,8 +9857,8 @@
         // when entering the lockdown mode, cancel the 2 notifications.
         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
-        mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
-        assertTrue(mStrongAuthTracker.isInLockDownMode());
+        mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+        assertTrue(mStrongAuthTracker.isInLockDownMode(0));
 
         // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
         ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
@@ -9866,10 +9867,46 @@
 
         // exit lockdown mode.
         mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
-        mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+        mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+        assertFalse(mStrongAuthTracker.isInLockDownMode(0));
 
         // the notifyPostedLocked function is called twice.
-        verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+        verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong());
+        //verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+    }
+
+    @Test
+    public void testMakeRankingUpdateLockedInLockDownMode() {
+        // post 2 notifications from a same package
+        NotificationRecord pkgA = new NotificationRecord(mContext,
+                generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+        mService.addNotification(pkgA);
+        NotificationRecord pkgB = new NotificationRecord(mContext,
+                generateSbn("a", 1000, 9, 1), mTestNotificationChannel);
+        mService.addNotification(pkgB);
+
+        mService.setIsVisibleToListenerReturnValue(true);
+        NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null);
+        assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
+
+        // when only user 0 entering the lockdown mode, its notification will be suppressed.
+        mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+                STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+        mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+        assertTrue(mStrongAuthTracker.isInLockDownMode(0));
+        assertFalse(mStrongAuthTracker.isInLockDownMode(1));
+
+        nru = mService.makeRankingUpdateLocked(null);
+        assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
+
+        // User 0 exits lockdown mode. Its notification will be resumed.
+        mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+        mStrongAuthTracker.onStrongAuthRequiredChanged(0);
+        assertFalse(mStrongAuthTracker.isInLockDownMode(0));
+        assertFalse(mStrongAuthTracker.isInLockDownMode(1));
+
+        nru = mService.makeRankingUpdateLocked(null);
+        assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
index b49e5cb..8cf74fb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
@@ -19,10 +19,12 @@
 import android.companion.ICompanionDeviceManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.service.notification.StatusBarNotification;
 
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.InstanceIdSequence;
+import com.android.server.notification.ManagedServices.ManagedServiceInfo;
 
 import java.util.HashSet;
 import java.util.Set;
@@ -37,6 +39,9 @@
     @Nullable
     NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
 
+    @Nullable
+    Boolean mIsVisibleToListenerReturnValue = null;
+
     TestableNotificationManagerService(Context context, NotificationRecordLogger logger,
             InstanceIdSequence notificationInstanceIdSequence) {
         super(context, logger, notificationInstanceIdSequence);
@@ -119,6 +124,19 @@
         mShowReviewPermissionsNotification = setting;
     }
 
+    protected void setIsVisibleToListenerReturnValue(boolean value) {
+        mIsVisibleToListenerReturnValue = value;
+    }
+
+    @Override
+    boolean isVisibleToListener(StatusBarNotification sbn, int notificationType,
+            ManagedServiceInfo listener) {
+        if (mIsVisibleToListenerReturnValue != null) {
+            return mIsVisibleToListenerReturnValue;
+        }
+        return super.isVisibleToListener(sbn, notificationType, listener);
+    }
+
     public class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker {
         private int mGetStrongAuthForUserReturnValue = 0;
         StrongAuthTrackerFake(Context context) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 6ed8460..333be7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2991,6 +2991,7 @@
         // Add a decor insets provider window.
         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
         squareDisplay.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(navbar);
+        squareDisplay.sendNewConfiguration();
         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
 
         // create a fixed portrait activity
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2204ae3..2b0e76c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -102,7 +102,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
 import com.android.server.wm.utils.MockTracker;
 
@@ -379,6 +379,8 @@
         doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
         doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(),
                 anyInt(), anyBoolean(), anyInt());
+        doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(),
+                anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt());
         doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
 
         // Never review permissions
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 20b1120..2fccd64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -220,10 +220,7 @@
         // Check that changes are reported
         Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration());
         c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300));
-        newDisp1.onRequestedOverrideConfigurationChanged(c);
-        mAtm.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
-                newDisp1.mDisplayId, false /* markFrozenIfConfigChanged */,
-                false /* deferResume */);
+        newDisp1.performDisplayOverrideConfigUpdate(c);
         assertEquals(0, added.size());
         assertEquals(1, changed.size());
         assertEquals(0, removed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index b5764f5..4d71b30 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -134,9 +134,9 @@
 
     @Test
     public void testNoChangeOnOldDisplayWhenMoveDisplay() {
-        mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        mDisplayContent.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
-        dc1.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        dc1.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FREEFORM);
         setUpOnDisplay(dc1);
 
         assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 7244d94..11ae5d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -139,6 +139,7 @@
 import android.view.WindowManager;
 import android.window.DisplayAreaInfo;
 import android.window.IDisplayAreaOrganizer;
+import android.window.ScreenCapture;
 import android.window.WindowContainerToken;
 
 import androidx.test.filters.SmallTest;
@@ -1067,6 +1068,7 @@
         final DisplayContent dc = createNewDisplay();
         dc.getDisplayRotation().setFixedToUserRotation(
                 IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
+        dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         final int newOrientation = getRotatedOrientation(dc);
 
         final Task task = new TaskBuilder(mSupervisor)
@@ -1126,6 +1128,7 @@
                 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
         dc.getDisplayRotation().setUserRotation(
                 WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0);
+        dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         final int newOrientation = getRotatedOrientation(dc);
 
         final Task task = new TaskBuilder(mSupervisor)
@@ -2032,23 +2035,6 @@
     }
 
     @Test
-    public void testSetWindowingModeAtomicallyUpdatesWindoingModeAndDisplayWindowingMode() {
-        final DisplayContent dc = createNewDisplay();
-        final Task rootTask = new TaskBuilder(mSupervisor)
-                .setDisplay(dc)
-                .build();
-        doAnswer(invocation -> {
-            Object[] args = invocation.getArguments();
-            final Configuration config = ((Configuration) args[0]);
-            assertEquals(config.windowConfiguration.getWindowingMode(),
-                    config.windowConfiguration.getDisplayWindowingMode());
-            return null;
-        }).when(rootTask).onConfigurationChanged(any());
-        dc.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        dc.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-    }
-
-    @Test
     public void testForceDesktopMode() {
         mWm.mForceDesktopModeOnExternalDisplays = true;
         // Not applicable for default display
@@ -2124,8 +2110,8 @@
 
         // Preparation: Simulate snapshot IME surface.
         spyOn(mWm.mTaskSnapshotController);
-        SurfaceControl.ScreenshotHardwareBuffer mockHwBuffer = mock(
-                SurfaceControl.ScreenshotHardwareBuffer.class);
+        ScreenCapture.ScreenshotHardwareBuffer mockHwBuffer = mock(
+                ScreenCapture.ScreenshotHardwareBuffer.class);
         doReturn(mock(HardwareBuffer.class)).when(mockHwBuffer).getHardwareBuffer();
         doReturn(mockHwBuffer).when(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(any());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 093be82..c398a0a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -110,7 +110,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                mPrimaryDisplay.getWindowingMode());
+                mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -120,7 +120,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                mPrimaryDisplay.getWindowingMode());
+                mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -131,7 +131,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                mPrimaryDisplay.getWindowingMode());
+                mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -141,7 +141,8 @@
 
         mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
 
-        assertEquals(WINDOWING_MODE_FREEFORM, mPrimaryDisplay.getWindowingMode());
+        assertEquals(WINDOWING_MODE_FREEFORM,
+                mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -154,7 +155,7 @@
         mDisplayWindowSettings.updateSettingsForDisplay(mPrimaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
-                mPrimaryDisplay.getWindowingMode());
+                mPrimaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -162,7 +163,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                mSecondaryDisplay.getWindowingMode());
+                mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -172,7 +173,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                mSecondaryDisplay.getWindowingMode());
+                mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -183,7 +184,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WINDOWING_MODE_FREEFORM,
-                mSecondaryDisplay.getWindowingMode());
+                mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
@@ -194,7 +195,7 @@
         mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
 
         assertEquals(WINDOWING_MODE_FREEFORM,
-                mSecondaryDisplay.getWindowingMode());
+                mSecondaryDisplay.getDefaultTaskDisplayArea().getWindowingMode());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 28fc352..4526d18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -467,8 +467,7 @@
             public void onAnimatorScaleChanged(float scale) {}
         });
         try {
-            session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION,
-                    TEST_UID);
+            session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
             fail("Expected failure without permission");
         } catch (SecurityException e) {
             // Expected failure
@@ -484,8 +483,7 @@
             public void onAnimatorScaleChanged(float scale) {}
         });
         try {
-            session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION,
-                    TEST_UID);
+            session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
             // Expected pass
         } catch (SecurityException e) {
             fail("Expected no failure with permission");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index ca8481a..c839d12 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -63,6 +63,7 @@
     public void testInputMethodInputTargetCanShowIme() {
         WindowState target = createWindow(null, TYPE_APPLICATION, "app");
         mDisplayContent.setImeLayeringTarget(target);
+        mDisplayContent.updateImeInputAndControlTarget(target);
         mImeProvider.scheduleShowImePostLayout(target);
         assertTrue(mImeProvider.isReadyToShowIme());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 9e658e0..4f03f54 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -108,9 +108,10 @@
     }
 
     @Test
-    public void testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved() {
+    public void testUpdateDefaultTaskDisplayAreaWindowingModeOnSettingsRetrieved() {
         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                mWm.getDefaultDisplayContentLocked().getWindowingMode());
+                mWm.getDefaultDisplayContentLocked().getDefaultTaskDisplayArea()
+                        .getWindowingMode());
 
         mWm.mIsPc = true;
         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
@@ -118,7 +119,8 @@
         mWm.mRoot.onSettingsRetrieved();
 
         assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
-                mWm.getDefaultDisplayContentLocked().getWindowingMode());
+                mWm.getDefaultDisplayContentLocked().getDefaultTaskDisplayArea()
+                        .getWindowingMode());
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 7111852..e57ad5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -17,9 +17,12 @@
 package com.android.server.wm;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
 
 import android.app.ActivityOptions;
 import android.platform.test.annotations.Presubmit;
+import android.window.WindowContainerToken;
 
 import androidx.test.filters.MediumTest;
 
@@ -43,4 +46,21 @@
         final ActivityOptions result = options.mergeActivityOptions(opts1, opts2);
         assertEquals(6, result.getLaunchDisplayId());
     }
+
+    @Test
+    public void test_selectiveCloneDisplayOptions() {
+        final WindowContainerToken token = mock(WindowContainerToken.class);
+        final int launchDisplayId = 5;
+        final int callerDisplayId = 6;
+
+        final SafeActivityOptions clone = new SafeActivityOptions(ActivityOptions.makeBasic()
+                .setLaunchTaskDisplayArea(token)
+                .setLaunchDisplayId(launchDisplayId)
+                .setCallerDisplayId(callerDisplayId))
+                .selectiveCloneDisplayOptions();
+
+        assertSame(clone.getOriginalOptions().getLaunchTaskDisplayArea(), token);
+        assertEquals(clone.getOriginalOptions().getLaunchDisplayId(), launchDisplayId);
+        assertEquals(clone.getOriginalOptions().getCallerDisplayId(), callerDisplayId);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
index f542e29..0b58428 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
@@ -36,6 +36,7 @@
 import android.view.PointerIcon;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
+import android.window.ScreenCapture;
 
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
@@ -98,11 +99,11 @@
                 .setColorSpace(secureSC, ColorSpace.get(ColorSpace.Named.SRGB))
                 .apply(true);
 
-        SurfaceControl.LayerCaptureArgs args = new SurfaceControl.LayerCaptureArgs.Builder(secureSC)
+        ScreenCapture.LayerCaptureArgs args = new ScreenCapture.LayerCaptureArgs.Builder(secureSC)
                 .setCaptureSecureLayers(true)
                 .setChildrenOnly(false)
                 .build();
-        SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = SurfaceControl.captureLayers(args);
+        ScreenCapture.ScreenshotHardwareBuffer hardwareBuffer = ScreenCapture.captureLayers(args);
         assertNotNull(hardwareBuffer);
 
         Bitmap screenshot = hardwareBuffer.asBitmap();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 646f43c..9f7f341 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -676,7 +676,8 @@
 
         // The non-resizable activity should not be size compat because the display support
         // changing windowing mode from fullscreen to freeform.
-        mTask.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+        mTask.mDisplayContent.getDefaultTaskDisplayArea()
+                .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
         mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
         assertFalse(activity.shouldCreateCompatDisplayInsets());
         // Activity should not be sandboxed.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index ff0063c..6c8a7ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -361,7 +361,7 @@
 
         @Override
         public Builder makeAnimationLeash() {
-            return new SurfaceControl.Builder(mSession) {
+            return new Builder(mSession) {
 
                 @Override
                 public SurfaceControl build() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 9e6c4c5..f5fc5c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -345,7 +345,7 @@
         // Set default display to be in fullscreen mode. Devices with PC feature may start their
         // default display in freeform mode but some of tests in WmTests have implicit assumption on
         // that the default display is in fullscreen mode.
-        display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        display.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         spyOn(display);
         final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 22101c2..aaf855f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1843,7 +1843,7 @@
 
     private TestDisplayContent createNewDisplayContent(int windowingMode) {
         final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
-        display.setWindowingMode(windowingMode);
+        display.getDefaultTaskDisplayArea().setWindowingMode(windowingMode);
         display.setBounds(DISPLAY_BOUNDS);
         display.getConfiguration().densityDpi = DENSITY_DEFAULT;
         display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
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 8e89d6f..e352d76 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1257,7 +1257,8 @@
 
         final Task task = getTestTask();
         task.setHasBeenVisible(false);
-        task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.getDisplayContent().getDefaultTaskDisplayArea()
+                .setWindowingMode(WINDOWING_MODE_FREEFORM);
         task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
         task.setHasBeenVisible(true);
@@ -1273,7 +1274,9 @@
 
         final Task task = getTestTask();
         task.setHasBeenVisible(false);
-        task.getDisplayContent().setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+        task.getDisplayContent()
+                .getDefaultTaskDisplayArea()
+                .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
         task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         final DisplayContent oldDisplay = task.getDisplayContent();
 
@@ -1313,7 +1316,8 @@
 
         final Task task = getTestTask();
         task.setHasBeenVisible(false);
-        task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.getDisplayContent().getDefaultTaskDisplayArea()
+                .setWindowingMode(WINDOWING_MODE_FREEFORM);
         task.getRootTask().setWindowingMode(WINDOWING_MODE_PINNED);
 
         task.setHasBeenVisible(true);
@@ -1330,7 +1334,8 @@
         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true)
                 .setCreateParentTask(true).build().getRootTask();
         task.setHasBeenVisible(false);
-        task.getDisplayContent().setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.getDisplayContent().getDefaultTaskDisplayArea()
+                .setWindowingMode(WINDOWING_MODE_FREEFORM);
         task.getRootTask().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
         final Task leafTask = createTaskInRootTask(task, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 048cd7c..64e15f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
@@ -31,7 +32,8 @@
 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.window.TransitionInfo.FLAG_IS_EMBEDDED;
+import static android.window.TransitionInfo.FLAG_FILLS_TASK;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -1065,12 +1067,14 @@
     }
 
     @Test
-    public void testIsEmbeddedChange() {
+    public void testFlagInTaskWithEmbeddedActivity() {
         final Transition transition = createTestTransition(TRANSIT_OPEN);
         final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
         final ArraySet<WindowContainer> participants = transition.mParticipants;
 
         final Task task = createTask(mDisplayContent);
+        final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
+        assertFalse(nonEmbeddedActivity.isEmbedded());
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
         mAtm.mTaskFragmentOrganizerController.registerOrganizer(
                 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
@@ -1085,20 +1089,72 @@
         changes.put(embeddedTf, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
         changes.put(closingActivity, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
         changes.put(openingActivity, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+        changes.put(nonEmbeddedActivity, new Transition.ChangeInfo(true /* vis */,
+                false /* exChg */));
         // End states.
         closingActivity.mVisibleRequested = false;
         openingActivity.mVisibleRequested = true;
+        nonEmbeddedActivity.mVisibleRequested = false;
 
         participants.add(closingActivity);
         participants.add(openingActivity);
+        participants.add(nonEmbeddedActivity);
         final ArrayList<WindowContainer> targets = Transition.calculateTargets(
                 participants, changes);
         final TransitionInfo info = Transition.calculateTransitionInfo(
                 transition.mType, 0 /* flags */, targets, changes, mMockT);
 
+        // All windows in the Task should have FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY because the Task
+        // contains embedded activity.
+        assertEquals(3, info.getChanges().size());
+        assertTrue(info.getChanges().get(0).hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY));
+        assertTrue(info.getChanges().get(1).hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY));
+        assertTrue(info.getChanges().get(2).hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY));
+    }
+
+    @Test
+    public void testFlagFillsTask() {
+        final Transition transition = createTestTransition(TRANSIT_OPEN);
+        final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        final ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task task = createTask(mDisplayContent);
+        // Set to multi-windowing mode in order to set bounds.
+        task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        final Rect taskBounds = new Rect(0, 0, 500, 1000);
+        task.setBounds(taskBounds);
+        final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
+        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+        mAtm.mTaskFragmentOrganizerController.registerOrganizer(
+                ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
+        final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .createActivityCount(1)
+                .setOrganizer(organizer)
+                .build();
+        final ActivityRecord embeddedActivity = embeddedTf.getTopMostActivity();
+        // Start states.
+        changes.put(task, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+        changes.put(nonEmbeddedActivity, new Transition.ChangeInfo(true /* vis */,
+                false /* exChg */));
+        changes.put(embeddedTf, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+        // End states.
+        nonEmbeddedActivity.mVisibleRequested = false;
+        embeddedActivity.mVisibleRequested = true;
+        embeddedTf.setBounds(new Rect(0, 0, 500, 500));
+
+        participants.add(nonEmbeddedActivity);
+        participants.add(embeddedTf);
+        final ArrayList<WindowContainer> targets = Transition.calculateTargets(
+                participants, changes);
+        final TransitionInfo info = Transition.calculateTransitionInfo(
+                transition.mType, 0 /* flags */, targets, changes, mMockT);
+
+        // The embedded with bounds overridden should not have the flag.
         assertEquals(2, info.getChanges().size());
-        assertTrue((info.getChanges().get(0).getFlags() & FLAG_IS_EMBEDDED) != 0);
-        assertTrue((info.getChanges().get(1).getFlags() & FLAG_IS_EMBEDDED) != 0);
+        assertFalse(info.getChanges().get(0).hasFlags(FLAG_FILLS_TASK));
+        assertEquals(embeddedTf.getBounds(), info.getChanges().get(0).getEndAbsBounds());
+        assertFalse(info.getChanges().get(1).hasFlags(FLAG_FILLS_TASK));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5c7b882..e8c8054 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -671,11 +671,9 @@
         verify(t, never()).setMatrix(any(), anyInt(), anyInt(), anyInt(), anyInt());
 
         // According to "dp * density / 160 = px", density is scaled and the size in dp is the same.
-        final CompatibilityInfo compatInfo = cmp.compatibilityInfoForPackageLocked(
-                mContext.getApplicationInfo());
         final Configuration winConfig = w.getConfiguration();
         final Configuration clientConfig = new Configuration(w.getConfiguration());
-        compatInfo.applyToConfiguration(clientConfig.densityDpi, clientConfig);
+        CompatibilityInfo.scaleConfiguration(w.mInvGlobalScale, clientConfig);
 
         assertEquals(winConfig.screenWidthDp, clientConfig.screenWidthDp);
         assertEquals(winConfig.screenHeightDp, clientConfig.screenHeightDp);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 353b757..4293d48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -97,6 +97,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
 import android.window.ITransitionPlayer;
+import android.window.ScreenCapture;
 import android.window.StartingWindowInfo;
 import android.window.StartingWindowRemovalInfo;
 import android.window.TaskFragmentOrganizer;
@@ -946,8 +947,8 @@
 
     /** Mocks the behavior of taking a snapshot. */
     void mockSurfaceFreezerSnapshot(SurfaceFreezer surfaceFreezer) {
-        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                mock(SurfaceControl.ScreenshotHardwareBuffer.class);
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+                mock(ScreenCapture.ScreenshotHardwareBuffer.class);
         final HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
         spyOn(surfaceFreezer);
         doReturn(screenshotBuffer).when(surfaceFreezer)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 77fca45..a95fa5a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -147,7 +147,7 @@
     }
 
     private static class HierarchyRecordingBuilderFactory implements Function<SurfaceSession,
-                SurfaceControl.Builder> {
+            SurfaceControl.Builder> {
         private LayerRecordingTransaction mTransaction;
 
         HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3023ec9..16f8fd9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -39,7 +39,6 @@
 import android.telecom.TelecomManager;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.data.ApnSetting;
-import android.telephony.data.DataCallResponse;
 import android.telephony.gba.TlsParams;
 import android.telephony.gba.UaSecurityProtocolIdentifier;
 import android.telephony.ims.ImsReasonInfo;
@@ -1136,27 +1135,6 @@
     public static final String KEY_DEFAULT_MTU_INT = "default_mtu_int";
 
     /**
-     * The data call retry configuration for different types of APN.
-     * @hide
-     */
-    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS =
-            "carrier_data_call_retry_config_strings";
-
-    /**
-     * Delay in milliseconds between trying APN from the pool
-     * @hide
-     */
-    public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
-            "carrier_data_call_apn_delay_default_long";
-
-    /**
-     * Faster delay in milliseconds between trying APN from the pool
-     * @hide
-     */
-    public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
-            "carrier_data_call_apn_delay_faster_long";
-
-    /**
      * Delay in milliseconds for retrying APN after disconnect
      * @hide
      */
@@ -1164,21 +1142,6 @@
             "carrier_data_call_apn_retry_after_disconnect_long";
 
     /**
-     * The maximum times for telephony to retry data setup on the same APN requested by
-     * network through the data setup response retry timer
-     * {@link DataCallResponse#getRetryDurationMillis()}. This is to prevent that network keeps
-     * asking device to retry data setup forever and causes power consumption issue. For infinite
-     * retring same APN, configure this as 2147483647 (i.e. {@link Integer#MAX_VALUE}).
-     *
-     * Note if network does not suggest any retry timer, frameworks uses the retry configuration
-     * from {@link #KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS}, and the maximum retry times could
-     * be configured there.
-     * @hide
-     */
-    public static final String KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT =
-            "carrier_data_call_retry_network_requested_max_count_int";
-
-    /**
      * Data call setup permanent failure causes by the carrier
      */
     public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
@@ -1239,19 +1202,6 @@
             "carrier_metered_roaming_apn_types_strings";
 
     /**
-     * APN types that are not allowed on cellular
-     * @hide
-     */
-    public static final String KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY =
-            "carrier_wwan_disallowed_apn_types_string_array";
-
-    /**
-     * APN types that are not allowed on IWLAN
-     * @hide
-     */
-    public static final String KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY =
-            "carrier_wlan_disallowed_apn_types_string_array";
-    /**
      * CDMA carrier ERI (Enhanced Roaming Indicator) file name
      * @hide
      */
@@ -8470,7 +8420,6 @@
      * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
      * 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
      *
-     * // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS
      * @hide
      */
     public static final String KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY =
@@ -8872,27 +8821,13 @@
         sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
         sDefaults.putInt(KEY_DEFAULT_MTU_INT, 1500);
-        sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
-                "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
-                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
-                "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
-                        + "320000:5000,640000:5000,1280000:5000,1800000:5000",
-                "ims:max_retries=10, 5000, 5000, 5000",
-                "others:max_retries=3, 5000, 5000, 5000"});
-        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
-        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
         sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 3000);
-        sDefaults.putInt(KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, 3);
         sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
         sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
         sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{"default", "mms", "dun", "supl"});
         sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{"default", "mms", "dun", "supl"});
-        sDefaults.putStringArray(KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
-                new String[]{""});
-        sDefaults.putStringArray(KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
-                new String[]{""});
         sDefaults.putIntArray(KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY,
                 new int[] {TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT,
                         TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index aa8011b..b4244dd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6893,11 +6893,11 @@
      *
      * @hide
      */
-    public void setCellInfoListRate(int rateInMillis) {
+    public void setCellInfoListRate(int rateInMillis, int subId) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                telephony.setCellInfoListRate(rateInMillis);
+                telephony.setCellInfoListRate(rateInMillis, subId);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index f794a79..6df9f9b 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1109,6 +1109,7 @@
         sb.append(", ").append(mCarrierId);
         sb.append(", ").append(mSkip464Xlat);
         sb.append(", ").append(mAlwaysOn);
+        sb.append(", ").append(Objects.hash(mUser, mPassword));
         return sb.toString();
     }
 
@@ -1297,8 +1298,6 @@
                 other.mLingeringNetworkTypeBitmask)
                 && Objects.equals(this.mProfileId, other.mProfileId)
                 && Objects.equals(this.mPersistent, other.mPersistent)
-                && Objects.equals(this.mMvnoType, other.mMvnoType)
-                && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
                 && Objects.equals(this.mApnSetId, other.mApnSetId)
                 && Objects.equals(this.mCarrierId, other.mCarrierId)
                 && Objects.equals(this.mSkip464Xlat, other.mSkip464Xlat)
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 42cac66..850d268 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -621,7 +621,7 @@
     /**
      * Sets minimum time in milli-seconds between onCellInfoChanged
      */
-    void setCellInfoListRate(int rateInMillis);
+    void setCellInfoListRate(int rateInMillis, int subId);
 
     /**
      * Opens a logical channel to the ICC card.
@@ -2548,9 +2548,6 @@
     CellIdentity getLastKnownCellIdentity(int subId, String callingPackage,
             String callingFeatureId);
 
-    /** Check if telephony new data stack is enabled. */
-    boolean isUsingNewDataStack();
-
     /**
      *  @return true if the modem service is set successfully, false otherwise.
      */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index 8df3548..1e798f3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -58,9 +58,7 @@
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
             setup {
-                test {
-                    testSpec.setIsTablet(wmHelper.currentState.wmState.isTablet)
-                }
+                testSpec.setIsTablet(wmHelper.currentState.wmState.isTablet)
             }
             transition()
         }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
index 1a40f82..34544ea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
@@ -49,21 +49,15 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-            }
+            tapl.setExpectedRotationCheckEnabled(false)
+            testApp.launchViaIntent(wmHelper)
         }
         transitions {
             testApp.launchPlaceholderSplit(wmHelper)
         }
         teardown {
-            test {
-                tapl.goHome()
-                testApp.exit(wmHelper)
-            }
+            tapl.goHome()
+            testApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 55d4129..1322a1c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -71,9 +71,7 @@
         get() = {
             super.transition(this)
             setup {
-                test {
-                    tapl.setExpectedRotationCheckEnabled(false)
-                }
+                tapl.setExpectedRotationCheckEnabled(false)
             }
             transitions {
                 // Can't use TAPL at the moment because of rotation test issues
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index cb197cd..f296d97 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -36,18 +36,12 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotation(testSpec.startRotation)
-            }
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-                this.setRotation(testSpec.startRotation)
-            }
+            tapl.setExpectedRotation(testSpec.startRotation)
+            testApp.launchViaIntent(wmHelper)
+            this.setRotation(testSpec.startRotation)
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
new file mode 100644
index 0000000..ea5a5f8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class GameAppHelper @JvmOverloads constructor(
+    instr: Instrumentation,
+    launcherName: String = ActivityOptions.GAME_ACTIVITY_LAUNCHER_NAME,
+    component: ComponentNameMatcher =
+        ActivityOptions.GAME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+    launcherStrategy: ILauncherStrategy =
+        LauncherStrategyFactory.getInstance(instr).launcherStrategy,
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+    /**
+     * Swipes down in the mock game app.
+     *
+     * @return true if the swipe operation is successful.
+     */
+    fun swipeDown(): Boolean {
+        val gameView = uiDevice.wait(
+            Until.findObject(By.res(getPackage(), GAME_APP_VIEW_RES)), WAIT_TIME_MS)
+        require(gameView != null) { "Mock game app view not found." }
+
+        val bound = gameView.getVisibleBounds()
+        return uiDevice.swipe(
+            bound.centerX(), bound.top, bound.centerX(), bound.centerY(), SWIPE_STEPS)
+    }
+
+    /**
+     * Switches to a recent app by quick switch gesture. This function can be used in both portrait
+     * and landscape mode.
+     *
+     * @param wmHelper Helper used to get window region.
+     * @param direction UiAutomator Direction enum to indicate the swipe direction.
+     *
+     * @return true if the swipe operation is successful.
+     */
+    fun switchToPreviousAppByQuickSwitchGesture(
+        wmHelper: WindowManagerStateHelper,
+        direction: Direction
+    ): Boolean {
+        val ratioForScreenBottom = 0.97
+        val fullView = wmHelper.getWindowRegion(componentMatcher)
+        require(!fullView.isEmpty) { "Target $componentMatcher view not found." }
+
+        val bound = fullView.bounds
+        val targetYPos = bound.bottom * ratioForScreenBottom
+        val endX = when (direction) {
+            Direction.LEFT -> bound.left
+            Direction.RIGHT -> bound.right
+            else -> {
+                throw IllegalStateException("Only left or right direction is allowed.")
+            }
+        }
+        return uiDevice.swipe(
+            bound.centerX(), targetYPos.toInt(), endX, targetYPos.toInt(), SWIPE_STEPS)
+    }
+
+    /**
+     * Waits for view idel with timeout, then checkes the target object whether visible on screen.
+     *
+     * @param packageName The targe application's package name.
+     * @param identifier The resource id of the target object.
+     * @param timeout The timeout duration in milliseconds.
+     *
+     * @return true if the target object exists.
+     */
+    @JvmOverloads
+    fun isTargetObjVisible(
+        packageName: String,
+        identifier: String,
+        timeout: Long = WAIT_TIME_MS
+    ): Boolean {
+        uiDevice.waitForIdle(timeout)
+        return uiDevice.hasObject(By.res(packageName, identifier))
+    }
+
+    companion object {
+        private const val GAME_APP_VIEW_RES = "container"
+        private const val WAIT_TIME_MS = 3_000L
+        private const val SWIPE_STEPS = 30
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
new file mode 100644
index 0000000..807e672
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Direction
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.parser.toFlickerComponent
+
+class MailAppHelper @JvmOverloads constructor(
+        instr: Instrumentation,
+        launcherName: String = ActivityOptions.MAIL_ACTIVITY_LAUNCHER_NAME,
+        component: ComponentNameMatcher =
+                ActivityOptions.MAIL_ACTIVITY_COMPONENT_NAME.toFlickerComponent(),
+        launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+                .getInstance(instr)
+                .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+    fun openMail(rowIdx: Int) {
+        val rowSel = By.res(getPackage(), "mail_row_item_text")
+            .textEndsWith(String.format("%04d", rowIdx))
+        var row: UiObject2? = null
+        for (i in 1..1000) {
+            row = uiDevice.wait(Until.findObject(rowSel), SHORT_WAIT_TIME_MS)
+            if (row != null) break
+            scrollDown()
+        }
+        require(row != null) {""}
+        row.click()
+        uiDevice.wait(Until.gone(By.res(getPackage(), MAIL_LIST_RES_ID)), FIND_TIMEOUT)
+    }
+
+    fun scrollDown() {
+        val listView = waitForMailList()
+        listView.scroll(Direction.DOWN, 1.0f)
+    }
+
+    fun waitForMailList(): UiObject2 {
+        var sel = By.res(getPackage(), MAIL_LIST_RES_ID).scrollable(true)
+        val ret = uiDevice.wait(Until.findObject(sel), FIND_TIMEOUT)
+        require(ret != null) {""}
+        return ret
+    }
+
+    companion object {
+        private const val SHORT_WAIT_TIME_MS = 5000L
+        private const val MAIL_LIST_RES_ID = "mail_recycle_view"
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 725c10a..479ac8e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -57,14 +57,10 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-            }
+            testApp.launchViaIntent(wmHelper)
         }
         teardown {
-            eachRun {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.closeIME(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 8832686..07b52a6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -57,17 +57,11 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-            }
+            tapl.setExpectedRotationCheckEnabled(false)
+            testApp.launchViaIntent(wmHelper)
         }
         teardown {
-            eachRun {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             tapl.goHome()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
index 71e0aa1..fec7727 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
@@ -46,13 +46,9 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            eachRun {
-                imeTestApp.launchViaIntent(wmHelper)
-                imeTestApp.openIME(wmHelper)
-            }
+            tapl.setExpectedRotationCheckEnabled(false)
+            imeTestApp.launchViaIntent(wmHelper)
+            imeTestApp.openIME(wmHelper)
         }
         transitions {
             imeTestApp.dismissDialog(wmHelper)
@@ -61,13 +57,11 @@
                 .waitForAndVerify()
         }
         teardown {
-            eachRun {
-                tapl.goHome()
-                wmHelper.StateSyncBuilder()
-                    .withHomeActivityVisible()
-                    .waitForAndVerify()
-                imeTestApp.exit(wmHelper)
-            }
+            tapl.goHome()
+            wmHelper.StateSyncBuilder()
+                .withHomeActivityVisible()
+                .waitForAndVerify()
+            imeTestApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 0f91fd5..50596f1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -50,17 +50,11 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                testApp.launchViaIntent(wmHelper)
-            }
-            eachRun {
-                testApp.openIME(wmHelper)
-            }
+            testApp.launchViaIntent(wmHelper)
+            testApp.openIME(wmHelper)
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.closeIME(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 007a4f1..17eb8f9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -49,13 +49,9 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-                testApp.openIME(wmHelper)
-            }
+            tapl.setExpectedRotationCheckEnabled(false)
+            testApp.launchViaIntent(wmHelper)
+            testApp.openIME(wmHelper)
         }
         transitions {
             tapl.goHome()
@@ -65,9 +61,7 @@
                 .waitForAndVerify()
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index 216e0eda..f0776c1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -55,22 +55,18 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-                wmHelper.StateSyncBuilder()
-                    .withImeShown()
-                    .waitForAndVerify()
-                testApp.startDialogThemedActivity(wmHelper)
-                // Verify IME insets isn't visible on dialog since it's non-IME focusable window
-                assertFalse(testApp.getInsetsVisibleFromDialog(ime()))
-                assertTrue(testApp.getInsetsVisibleFromDialog(statusBars()))
-                assertTrue(testApp.getInsetsVisibleFromDialog(navigationBars()))
-            }
+            testApp.launchViaIntent(wmHelper)
+            wmHelper.StateSyncBuilder()
+                .withImeShown()
+                .waitForAndVerify()
+            testApp.startDialogThemedActivity(wmHelper)
+            // Verify IME insets isn't visible on dialog since it's non-IME focusable window
+            assertFalse(testApp.getInsetsVisibleFromDialog(ime()))
+            assertTrue(testApp.getInsetsVisibleFromDialog(statusBars()))
+            assertTrue(testApp.getInsetsVisibleFromDialog(navigationBars()))
         }
         teardown {
-            eachRun {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.dismissDialog(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
index 868290e..85e9e75 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -74,16 +74,12 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                initializeApp.launchViaIntent(wmHelper)
-                this.setRotation(testSpec.startRotation)
-            }
+            initializeApp.launchViaIntent(wmHelper)
+            this.setRotation(testSpec.startRotation)
         }
         teardown {
-            eachRun {
-                initializeApp.exit(wmHelper)
-                testApp.exit(wmHelper)
-            }
+            initializeApp.exit(wmHelper)
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.launchViaIntent(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
index 16c23b9..d42a6c3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
@@ -52,19 +52,15 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                simpleApp.launchViaIntent(wmHelper)
-                testApp.launchViaIntent(wmHelper)
-                testApp.openIME(wmHelper)
-            }
+            simpleApp.launchViaIntent(wmHelper)
+            testApp.launchViaIntent(wmHelper)
+            testApp.openIME(wmHelper)
         }
         transitions {
             testApp.finishActivity(wmHelper)
         }
         teardown {
-            test {
-                simpleApp.exit(wmHelper)
-            }
+            simpleApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index e587492..5f025f9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -54,20 +54,16 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            test {
-                // Launch the activity with expecting IME will be shown.
-                imeTestApp.launchViaIntent(wmHelper)
-            }
-            eachRun {
-                // Swiping out the IME activity to home.
-                tapl.goHome()
-                wmHelper.StateSyncBuilder()
-                    .withHomeActivityVisible()
-                    .waitForAndVerify()
-            }
+            tapl.setExpectedRotationCheckEnabled(false)
+
+            // Launch the activity with expecting IME will be shown.
+            imeTestApp.launchViaIntent(wmHelper)
+
+            // Swiping out the IME activity to home.
+            tapl.goHome()
+            wmHelper.StateSyncBuilder()
+                .withHomeActivityVisible()
+                .waitForAndVerify()
         }
         transitions {
             // Bring the exist IME activity to the front in landscape mode device rotation.
@@ -75,14 +71,12 @@
             imeTestApp.launchViaIntent(wmHelper)
         }
         teardown {
-            test {
-                imeTestApp.exit(wmHelper)
-            }
+            imeTestApp.exit(wmHelper)
         }
     }
 
     /** {@inheritDoc} */
-    @Postsubmit
+    @Presubmit
     @Test
     override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index c1f17f3..84b0f60 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -48,20 +48,14 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                testApp.launchViaIntent(wmHelper)
-            }
+            testApp.launchViaIntent(wmHelper)
         }
         transitions {
             testApp.openIME(wmHelper)
         }
         teardown {
-            eachRun {
-                testApp.closeIME(wmHelper)
-            }
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.closeIME(wmHelper)
+            testApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
index 5fd9442..f4d8f5b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
@@ -57,9 +57,7 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                imeTestApp.launchViaIntent(wmHelper)
-            }
+            imeTestApp.launchViaIntent(wmHelper)
         }
         transitions {
             device.pressRecentApps()
@@ -69,13 +67,11 @@
             builder.waitForAndVerify()
         }
         teardown {
-            test {
-                device.pressHome()
-                wmHelper.StateSyncBuilder()
-                    .withHomeActivityVisible()
-                    .waitForAndVerify()
-                imeTestApp.exit(wmHelper)
-            }
+            device.pressHome()
+            wmHelper.StateSyncBuilder()
+                .withHomeActivityVisible()
+                .waitForAndVerify()
+            imeTestApp.exit(wmHelper)
         }
     }
 
@@ -134,6 +130,7 @@
     @Presubmit
     @Test
     fun navBarLayerIsInvisibleInLandscapeGestural() {
+        Assume.assumeFalse(testSpec.isTablet)
         Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
         Assume.assumeTrue(testSpec.isGesturalNavigation)
         Assume.assumeTrue(isShellTransitionsEnabled)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 0281a60..f7e5b23 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -52,17 +52,13 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
                 testApp.launchViaIntent(wmHelper)
                 testApp.openIME(wmHelper)
-            }
-            eachRun {
                 this.setRotation(testSpec.startRotation)
                 device.pressRecentApps()
                 wmHelper.StateSyncBuilder()
                     .withRecentsActivityVisible()
                     .waitForAndVerify()
-            }
         }
         transitions {
             device.reopenAppFromOverview(wmHelper)
@@ -72,9 +68,7 @@
                 .waitForAndVerify()
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 85bf6d7..b75183d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -64,33 +64,27 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            eachRun {
-                this.setRotation(testSpec.startRotation)
-                testApp.launchViaIntent(wmHelper)
-                wmHelper.StateSyncBuilder()
-                    .withFullScreenApp(testApp)
-                    .waitForAndVerify()
+            tapl.setExpectedRotationCheckEnabled(false)
+            this.setRotation(testSpec.startRotation)
+            testApp.launchViaIntent(wmHelper)
+            wmHelper.StateSyncBuilder()
+                .withFullScreenApp(testApp)
+                .waitForAndVerify()
 
-                imeTestApp.launchViaIntent(wmHelper)
-                wmHelper.StateSyncBuilder()
-                    .withFullScreenApp(imeTestApp)
-                    .waitForAndVerify()
+            imeTestApp.launchViaIntent(wmHelper)
+            wmHelper.StateSyncBuilder()
+                .withFullScreenApp(imeTestApp)
+                .waitForAndVerify()
 
-                imeTestApp.openIME(wmHelper)
-            }
+            imeTestApp.openIME(wmHelper)
         }
         teardown {
-            eachRun {
-                tapl.goHome()
-                wmHelper.StateSyncBuilder()
-                    .withHomeActivityVisible()
-                    .waitForAndVerify()
-                testApp.exit(wmHelper)
-                imeTestApp.exit(wmHelper)
-            }
+            tapl.goHome()
+            wmHelper.StateSyncBuilder()
+                .withHomeActivityVisible()
+                .waitForAndVerify()
+            testApp.exit(wmHelper)
+            imeTestApp.exit(wmHelper)
         }
         transitions {
             // [Step1]: Swipe right from imeTestApp to testApp task
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index eb9acc4..08d7be2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -62,15 +62,11 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotation(testSpec.startRotation)
-                testApp.launchViaIntent(wmHelper)
-            }
+            tapl.setExpectedRotation(testSpec.startRotation)
+            testApp.launchViaIntent(wmHelper)
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.openSecondActivity(device, wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
index 3ff59e9..5eba78c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
@@ -52,21 +52,15 @@
         get() = {
             super.transition(this)
             setup {
-                test{
-                    tapl.setExpectedRotationCheckEnabled(false)
-                }
-                eachRun {
-                    // 1. Open camera - cold -> close it first
-                    cameraApp.exit(wmHelper)
-                    cameraApp.launchViaIntent(wmHelper)
-                    // 2. Press home button (button nav mode) / swipe up to home (gesture nav mode)
-                    tapl.goHome()
-                }
+                tapl.setExpectedRotationCheckEnabled(false)
+                // 1. Open camera - cold -> close it first
+                cameraApp.exit(wmHelper)
+                cameraApp.launchViaIntent(wmHelper)
+                // 2. Press home button (button nav mode) / swipe up to home (gesture nav mode)
+                tapl.goHome()
             }
             teardown {
-                eachRun {
-                    testApp.exit(wmHelper)
-                }
+                testApp.exit(wmHelper)
             }
             transitions {
                 testApp.launchViaIntent(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
index accf8af..9b1c541 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
@@ -62,16 +62,13 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
+                if (testSpec.isTablet) {
+                    tapl.setExpectedRotation(testSpec.startRotation)
+                } else {
                     tapl.setExpectedRotation(Surface.ROTATION_0)
-                    RemoveAllTasksButHomeRule.removeAllTasksButHome()
-                    this.setRotation(testSpec.startRotation)
                 }
-            }
-            teardown {
-                eachRun {
-                    testApp.exit(wmHelper)
-                }
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                this.setRotation(testSpec.startRotation)
             }
             transitions {
                 tapl.goHome()
@@ -79,6 +76,9 @@
                     .getAppIcon(testApp.launcherName)
                     .launch(testApp.`package`)
             }
+            teardown {
+                testApp.exit(wmHelper)
+            }
         }
 
     /** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index cd01f74..2c77668 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -64,15 +64,11 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    removeAllTasksButHome()
-                    this.setRotation(testSpec.startRotation)
-                }
+                removeAllTasksButHome()
+                this.setRotation(testSpec.startRotation)
             }
             teardown {
-                eachRun {
-                    testApp.exit(wmHelper)
-                }
+                testApp.exit(wmHelper)
             }
             transitions {
                 testApp.launchViaIntent(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index b3db5b70..b70bdd7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -64,12 +64,10 @@
 
             // Needs to run at the end of the setup, so after the setup defined in super.transition
             setup {
-                eachRun {
-                    device.sleep()
-                    wmHelper.StateSyncBuilder()
-                        .withoutTopVisibleAppWindows()
-                        .waitForAndVerify()
-                }
+                device.sleep()
+                wmHelper.StateSyncBuilder()
+                    .withoutTopVisibleAppWindows()
+                    .waitForAndVerify()
             }
         }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 8c1d244..48602c4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -68,12 +68,10 @@
 
             // Needs to run at the end of the setup, so after the setup defined in super.transition
             setup {
-                eachRun {
-                    device.sleep()
-                    wmHelper.StateSyncBuilder()
-                        .withoutTopVisibleAppWindows()
-                        .waitForAndVerify()
-                }
+                device.sleep()
+                wmHelper.StateSyncBuilder()
+                    .withoutTopVisibleAppWindows()
+                    .waitForAndVerify()
             }
         }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index caf2e2d..83350ea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -59,26 +59,22 @@
             super.transition(this)
 
             setup {
-                eachRun {
-                    device.wakeUpAndGoToHomeScreen()
+                device.wakeUpAndGoToHomeScreen()
 
-                    // Launch an activity that is shown when the device is locked
-                    showWhenLockedApp.launchViaIntent(wmHelper)
-                    wmHelper.StateSyncBuilder()
-                        .withFullScreenApp(showWhenLockedApp)
-                        .waitForAndVerify()
+                // Launch an activity that is shown when the device is locked
+                showWhenLockedApp.launchViaIntent(wmHelper)
+                wmHelper.StateSyncBuilder()
+                    .withFullScreenApp(showWhenLockedApp)
+                    .waitForAndVerify()
 
-                    device.sleep()
-                    wmHelper.StateSyncBuilder()
-                        .withoutTopVisibleAppWindows()
-                        .waitForAndVerify()
-                }
+                device.sleep()
+                wmHelper.StateSyncBuilder()
+                    .withoutTopVisibleAppWindows()
+                    .waitForAndVerify()
             }
 
             teardown {
-                test {
-                    showWhenLockedApp.exit(wmHelper)
-                }
+                showWhenLockedApp.exit(wmHelper)
             }
         }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
index ecc60b8..f574c9e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
@@ -39,17 +39,13 @@
     override val transition: FlickerBuilder.() -> Unit = {
         super.transition(this)
         setup {
-            eachRun {
-                device.sleep()
-                wmHelper.StateSyncBuilder()
-                    .withoutTopVisibleAppWindows()
-                    .waitForAndVerify()
-            }
+            device.sleep()
+            wmHelper.StateSyncBuilder()
+                .withoutTopVisibleAppWindows()
+                .waitForAndVerify()
         }
         teardown {
-            eachRun {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.launchViaIntent(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index e744d44..8d349a6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -24,7 +24,6 @@
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import org.junit.FixMethodOrder
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -51,101 +50,14 @@
             super.transition(this)
 
             setup {
-                eachRun {
-                    // Close the app that posted the notification to trigger a cold start next time
-                    // it is open - can't just kill it because that would remove the notification.
-                    tapl.goHome()
-                    tapl.workspace.switchToOverview()
-                    tapl.overview.dismissAllTasks()
-                }
+                // Close the app that posted the notification to trigger a cold start next time
+                // it is open - can't just kill it because that would remove the notification.
+                tapl.goHome()
+                tapl.workspace.switchToOverview()
+                tapl.overview.dismissAllTasks()
             }
         }
 
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerIsVisibleAtStartAndEnd() =
-        super.statusBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun notificationAppWindowVisibleAtEnd() = super.notificationAppWindowVisibleAtEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun notificationAppWindowOnTopAtEnd() = super.notificationAppWindowOnTopAtEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun notificationAppLayerVisibleAtEnd() = super.notificationAppLayerVisibleAtEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun appWindowBecomesTopWindow() = super.appWindowBecomesTopWindow()
-
-    /** {@inheritDoc} */
-    @Test
-    @Postsubmit
-    override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
-
-    /** {@inheritDoc} */
-    @Test
-    @Postsubmit
-    override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun appWindowIsTopWindowAtEnd() =
-        super.appWindowIsTopWindowAtEnd()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index 4ea4243..77f28f6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -67,21 +67,17 @@
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             setup {
-                test {
-                    device.wakeUpAndGoToHomeScreen()
-                    this.setRotation(testSpec.startRotation)
-                }
-                eachRun {
-                    testApp.launchViaIntent(wmHelper)
-                    wmHelper.StateSyncBuilder()
-                        .withFullScreenApp(testApp)
-                        .waitForAndVerify()
-                    testApp.postNotification(wmHelper)
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                }
+                device.wakeUpAndGoToHomeScreen()
+                this.setRotation(testSpec.startRotation)
+                testApp.launchViaIntent(wmHelper)
+                wmHelper.StateSyncBuilder()
+                    .withFullScreenApp(testApp)
+                    .waitForAndVerify()
+                testApp.postNotification(wmHelper)
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
             }
 
             transitions {
@@ -125,9 +121,7 @@
             }
 
             teardown {
-                test {
-                    testApp.exit(wmHelper)
-                }
+                testApp.exit(wmHelper)
             }
         }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index a3dd0cb..bc86cdf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -69,27 +69,23 @@
         get() = {
             super.transition(this)
             setup {
-                test {
-                    tapl.setExpectedRotationCheckEnabled(false)
-                    testApp.launchViaIntent(wmHelper)
+                tapl.setExpectedRotationCheckEnabled(false)
+                testApp.launchViaIntent(wmHelper)
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
+                // By default, launcher doesn't rotate on phones, but rotates on tablets
+                if (testSpec.isTablet) {
+                    tapl.setExpectedRotation(testSpec.startRotation)
+                } else {
+                    tapl.setExpectedRotation(Surface.ROTATION_0)
                 }
-                eachRun {
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                    // By default, launcher doesn't rotate on phones, but rotates on tablets
-                    if (testSpec.isTablet) {
-                        tapl.setExpectedRotation(testSpec.startRotation)
-                    } else {
-                        tapl.setExpectedRotation(Surface.ROTATION_0)
-                    }
-                    tapl.workspace.switchToOverview()
-                    wmHelper.StateSyncBuilder()
-                        .withRecentsActivityVisible()
-                        .waitForAndVerify()
-                    this.setRotation(testSpec.startRotation)
-                }
+                tapl.workspace.switchToOverview()
+                wmHelper.StateSyncBuilder()
+                    .withRecentsActivityVisible()
+                    .waitForAndVerify()
+                this.setRotation(testSpec.startRotation)
             }
             transitions {
                 tapl.overview.currentTask.open()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 8658c03..face7da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -36,16 +36,12 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotation(testSpec.startRotation)
-                device.wakeUpAndGoToHomeScreen()
-                this.setRotation(testSpec.startRotation)
-            }
+            tapl.setExpectedRotation(testSpec.startRotation)
+            device.wakeUpAndGoToHomeScreen()
+            this.setRotation(testSpec.startRotation)
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 4f69f01..8077398 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -65,22 +65,16 @@
         get() = {
             super.transition(this)
             setup {
-                test {
-                    tapl.setExpectedRotationCheckEnabled(false)
-                    testApp.launchViaIntent(wmHelper)
-                }
-                eachRun {
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                    this.setRotation(testSpec.startRotation)
-                }
+                tapl.setExpectedRotationCheckEnabled(false)
+                testApp.launchViaIntent(wmHelper)
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
+                this.setRotation(testSpec.startRotation)
             }
             teardown {
-                test {
-                    testApp.exit(wmHelper)
-                }
+                testApp.exit(wmHelper)
             }
             transitions {
                 testApp.launchViaIntent(wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 5f342a0..26f46cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -65,14 +65,10 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-            }
+            testApp.launchViaIntent(wmHelper)
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             testApp.openNewTask(device, wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index f85bad3..a1df1df 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
 import android.view.Surface
@@ -70,15 +69,11 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotation(testSpec.startRotation)
-            }
-            eachRun {
-                testApp1.launchViaIntent(wmHelper)
-                testApp2.launchViaIntent(wmHelper)
-                startDisplayBounds = wmHelper.currentState.layerState
-                    .physicalDisplayBounds ?: error("Display not found")
-            }
+            tapl.setExpectedRotation(testSpec.startRotation)
+            testApp1.launchViaIntent(wmHelper)
+            testApp2.launchViaIntent(wmHelper)
+            startDisplayBounds = wmHelper.currentState.layerState
+                .physicalDisplayBounds ?: error("Display not found")
         }
         transitions {
             tapl.launchedAppState.quickSwitchToPreviousApp()
@@ -90,10 +85,8 @@
         }
 
         teardown {
-            test {
-                testApp1.exit(wmHelper)
-                testApp2.exit(wmHelper)
-            }
+            testApp1.exit(wmHelper)
+            testApp2.exit(wmHelper)
         }
     }
 
@@ -266,7 +259,7 @@
     }
 
     /** {@inheritDoc} */
-    @Postsubmit
+    @Presubmit
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
index 461bae4..49dcbcf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -57,29 +56,6 @@
         Assume.assumeTrue(isShellTransitionsEnabled)
     }
 
-    @FlakyTest(bugId = 228009808)
-    @Test
-    override fun app1LayerIsVisibleOnceApp2LayerIsInvisible() =
-        super.app1LayerIsVisibleOnceApp2LayerIsInvisible()
-
-    @FlakyTest(bugId = 228009808)
-    @Test
-    override fun app1WindowBecomesAndStaysVisible() = super.app1WindowBecomesAndStaysVisible()
-
-    @FlakyTest(bugId = 228009808)
-    @Test
-    override fun endsWithApp1BeingOnTop() = super.endsWithApp1BeingOnTop()
-
-    @FlakyTest(bugId = 239147075)
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @FlakyTest(bugId = 239147075)
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
     /** {@inheritDoc} */
     @Ignore("Nav bar window becomes invisible during quick switch")
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index f6392ca..5ab9f14 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
 import android.view.Surface
@@ -71,10 +69,8 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
                 tapl.setExpectedRotation(testSpec.startRotation)
-            }
-            eachRun {
+
                 testApp1.launchViaIntent(wmHelper)
                 testApp2.launchViaIntent(wmHelper)
                 tapl.launchedAppState.quickSwitchToPreviousApp()
@@ -85,7 +81,6 @@
                     .waitForAndVerify()
                 startDisplayBounds = wmHelper.currentState.layerState
                     .physicalDisplayBounds ?: error("Display not found")
-            }
         }
         transitions {
             tapl.launchedAppState.quickSwitchToPreviousAppSwipeLeft()
@@ -97,10 +92,8 @@
         }
 
         teardown {
-            test {
-                testApp1.exit(wmHelper)
-                testApp2.exit(wmHelper)
-            }
+            testApp1.exit(wmHelper)
+            testApp2.exit(wmHelper)
         }
     }
 
@@ -274,22 +267,10 @@
     }
 
     /** {@inheritDoc} */
-    @Postsubmit
+    @Presubmit
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
-    /** {@inheritDoc} */
-    @FlakyTest(bugId = 239148258)
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
-    @FlakyTest(bugId = 239148258)
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
     companion object {
         private var startDisplayBounds = Rect.EMPTY
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt
index f644b97..7c7be89 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt
@@ -16,7 +16,6 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -57,19 +56,6 @@
         Assume.assumeTrue(isShellTransitionsEnabled)
     }
 
-    @FlakyTest(bugId = 228009808)
-    @Test
-    override fun app2LayerIsVisibleOnceApp1LayerIsInvisible() =
-        super.app2LayerIsVisibleOnceApp1LayerIsInvisible()
-
-    @FlakyTest(bugId = 228009808)
-    @Test
-    override fun app2WindowBecomesAndStaysVisible() = super.app2WindowBecomesAndStaysVisible()
-
-    @FlakyTest(bugId = 228009808)
-    @Test
-    override fun endsWithApp2BeingOnTop() = super.endsWithApp2BeingOnTop()
-
     /** {@inheritDoc} */
     @Ignore("Nav bar window becomes invisible during quick switch")
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index a714111..00e6023 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.platform.test.annotations.FlakyTest
-import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
 import android.view.Surface
@@ -62,24 +60,19 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            test {
-                tapl.setExpectedRotationCheckEnabled(false)
-            }
-            test {
-                tapl.setExpectedRotation(testSpec.startRotation)
-            }
+            tapl.setExpectedRotationCheckEnabled(false)
 
-            eachRun {
-                testApp.launchViaIntent(wmHelper)
-                tapl.goHome()
-                wmHelper.StateSyncBuilder()
-                    .withHomeActivityVisible()
-                    .withWindowSurfaceDisappeared(testApp)
-                    .waitForAndVerify()
+            tapl.setExpectedRotation(testSpec.startRotation)
 
-                startDisplayBounds = wmHelper.currentState.layerState
-                    .physicalDisplayBounds ?: error("Display not found")
-            }
+            testApp.launchViaIntent(wmHelper)
+            tapl.goHome()
+            wmHelper.StateSyncBuilder()
+                .withHomeActivityVisible()
+                .withWindowSurfaceDisappeared(testApp)
+                .waitForAndVerify()
+
+            startDisplayBounds = wmHelper.currentState.layerState
+                .physicalDisplayBounds ?: error("Display not found")
         }
         transitions {
             tapl.workspace.quickSwitchToPreviousApp()
@@ -89,11 +82,8 @@
                 .withStatusBarVisible()
                 .waitForAndVerify()
         }
-
         teardown {
-            eachRun {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
     }
 
@@ -284,22 +274,11 @@
     }
 
     /** {@inheritDoc} */
-    @Postsubmit
+    @Presubmit
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
-    @FlakyTest(bugId = 239148258)
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
-    @FlakyTest(bugId = 239148258)
-    @Test
-    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
-        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
-    /** {@inheritDoc} */
     @Ignore("Nav bar window becomes invisible during quick switch")
     @Test
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index e6c1eac..f24f71e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -80,9 +80,7 @@
         get() = {
             super.transition(this)
             setup {
-                test {
-                    testApp.launchViaIntent(wmHelper)
-                }
+                testApp.launchViaIntent(wmHelper)
             }
         }
 
@@ -129,12 +127,6 @@
     override fun navBarLayerPositionAtStartAndEnd() =
         super.navBarLayerPositionAtStartAndEnd()
 
-    /** {@inheritDoc} */
-    @FlakyTest
-    @Test
-    override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
-        super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 7e159d4..afe2ea6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -34,14 +34,10 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            eachRun {
-                this.setRotation(testSpec.startRotation)
-            }
+            this.setRotation(testSpec.startRotation)
         }
         teardown {
-            test {
-                testApp.exit(wmHelper)
-            }
+            testApp.exit(wmHelper)
         }
         transitions {
             this.setRotation(testSpec.endRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 07c2130..16ad630 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -87,15 +87,13 @@
         get() = {
             super.transition(this)
             setup {
-                test {
-                    testApp.launchViaIntent(
-                        wmHelper,
-                        stringExtras = mapOf(
-                            ActivityOptions.EXTRA_STARVE_UI_THREAD
-                                to testSpec.starveUiThread.toString()
-                        )
+                testApp.launchViaIntent(
+                    wmHelper,
+                    stringExtras = mapOf(
+                        ActivityOptions.EXTRA_STARVE_UI_THREAD
+                            to testSpec.starveUiThread.toString()
                     )
-                }
+                )
             }
         }
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 61aadaac..54662ef 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -202,5 +202,17 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".GameActivity"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.GameActivity"
+            android:immersive="true"
+            android:theme="@android:style/Theme.NoTitleBar"
+            android:configChanges="screenSize"
+            android:label="GameApp"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
new file mode 100644
index 0000000..0b4693d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/holo_orange_light">
+
+    <SurfaceView
+        android:id="@+id/surface_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 19fafb7..cae3df4 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -100,4 +100,13 @@
             ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
                     FLICKER_APP_PACKAGE,
             FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
+
+    public static final String MAIL_ACTIVITY_LAUNCHER_NAME = "MailActivity";
+    public static final ComponentName MAIL_ACTIVITY_COMPONENT_NAME = new ComponentName(
+            FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".MailActivity");
+
+    public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
+    public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                   FLICKER_APP_PACKAGE + ".GameActivity");
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
new file mode 100644
index 0000000..ef75d4d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.core.view.WindowInsetsControllerCompat;
+
+public class GameActivity extends Activity implements SurfaceHolder.Callback {
+    private SurfaceHolder mSurfaceHolder;
+    private SurfaceView mSurfaceView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_surfaceview);
+
+        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
+        mSurfaceView.setZOrderOnTop(true);
+        mSurfaceHolder = mSurfaceView.getHolder();
+        mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
+        mSurfaceHolder.addCallback(this);
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        hideSystemBars();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        Canvas canvas = holder.lockCanvas();
+        canvas.drawColor(Color.BLUE);
+        holder.unlockCanvasAndPost(canvas);
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+
+    private void hideSystemBars() {
+        WindowInsetsControllerCompat windowInsetsController =
+                ViewCompat.getWindowInsetsController(getWindow().getDecorView());
+        if (windowInsetsController == null) {
+            return;
+        }
+        // Configure the behavior of the hidden system bars.
+        windowInsetsController.setSystemBarsBehavior(
+                WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+        );
+        // Hide both the status bar and the navigation bar.
+        windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
+    }
+}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index b0ccbd1..939c7de 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -436,6 +436,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="SurfaceViewAlphaActivity"
+             android:label="SurfaceView/SurfaceView with Alpha"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.android.test.hwui.TEST"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name=".PenStylusActivity"
                   android:label="Pen/Draw"
                   android:exported="true">
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
new file mode 100644
index 0000000..01fe6ae0
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class SurfaceViewAlphaActivity extends Activity implements Callback {
+    SurfaceView mSurfaceView;
+
+    private enum ZOrder {
+        ABOVE,
+        BELOW
+    }
+
+    private float mAlpha = 127f / 255f;
+    private ZOrder mZOrder = ZOrder.BELOW;
+
+
+    private String getAlphaText() {
+        return "Alpha: " + mAlpha;
+    }
+
+    private void toggleZOrder() {
+        if (ZOrder.ABOVE.equals(mZOrder)) {
+            mZOrder = ZOrder.BELOW;
+        } else {
+            mZOrder = ZOrder.ABOVE;
+        }
+    }
+
+    // Overlaps a blue view on the left, then the SurfaceView in the center, then a blue view on the
+    // right.
+    private void overlapViews(SurfaceView view, LinearLayout parent) {
+        float density = getResources().getDisplayMetrics().density;
+        int surfaceViewSize = (int) (200 * density);
+        int blueViewSize = (int) (surfaceViewSize * 2 / 3f);
+        int totalSize = (int) (surfaceViewSize * 5 / 3f);
+
+        RelativeLayout overlapLayout = new RelativeLayout(this);
+
+        RelativeLayout.LayoutParams leftViewLayoutParams = new RelativeLayout.LayoutParams(
+                blueViewSize, surfaceViewSize);
+        leftViewLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+
+        View leftBlueView = new View(this);
+        leftBlueView.setBackgroundColor(Color.BLUE);
+        overlapLayout.addView(leftBlueView, leftViewLayoutParams);
+
+        RelativeLayout.LayoutParams sVLayoutParams = new RelativeLayout.LayoutParams(
+                surfaceViewSize, surfaceViewSize);
+        sVLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+        overlapLayout.addView(view, sVLayoutParams);
+
+        RelativeLayout.LayoutParams rightViewLayoutParams = new RelativeLayout.LayoutParams(
+                blueViewSize, surfaceViewSize);
+        rightViewLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+
+        View rightBlueView = new View(this);
+        rightBlueView.setBackgroundColor(Color.BLUE);
+        overlapLayout.addView(rightBlueView, rightViewLayoutParams);
+
+        parent.addView(overlapLayout, new LinearLayout.LayoutParams(
+                totalSize, surfaceViewSize));
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mSurfaceView = new SurfaceView(this);
+        mSurfaceView.getHolder().addCallback(this);
+        mSurfaceView.setAlpha(mAlpha);
+
+        LinearLayout content = new LinearLayout(this);
+        content.setOrientation(LinearLayout.VERTICAL);
+
+        TextView alphaText = new TextView(this);
+        alphaText.setText(getAlphaText());
+
+        SeekBar alphaToggle = new SeekBar(this);
+        alphaToggle.setMin(0);
+        alphaToggle.setMax(255);
+        alphaToggle.setProgress(Math.round(mAlpha * 255));
+        alphaToggle.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                mAlpha = progress / 255f;
+                alphaText.setText(getAlphaText());
+                mSurfaceView.setAlpha(mAlpha);
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+
+            }
+        });
+
+        content.addView(alphaText, new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT));
+
+        content.addView(alphaToggle, new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.MATCH_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT));
+
+        Button button = new Button(this);
+        button.setText("Z " + mZOrder.toString());
+        button.setOnClickListener(v -> {
+            toggleZOrder();
+            mSurfaceView.setZOrderOnTop(ZOrder.ABOVE.equals(mZOrder));
+            button.setText("Z " + mZOrder.toString());
+        });
+
+        content.addView(button, new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT));
+
+        overlapViews(mSurfaceView, content);
+
+        setContentView(content);
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        Canvas canvas = holder.lockCanvas();
+        canvas.drawColor(Color.RED);
+        holder.unlockCanvasAndPost(canvas);
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+}
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
index 836d406..06a96df 100644
--- a/tests/Input/src/com/android/test/input/InputDeviceTest.java
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -69,13 +69,25 @@
     }
 
     private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) {
-        final InputDevice device =
-                new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name",
-                        0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
-                        0 /* sources */, 0 /* keyboardType */, keyCharacterMap,
-                        InputDeviceCountryCode.INTERNATIONAL, false /* hasVibrator */,
-                        false /* hasMicrophone */, false /* hasButtonUnderpad */,
-                        true /* hasSensor */, false /* hasBattery */);
+        final InputDevice device = new InputDevice.Builder()
+                .setId(DEVICE_ID)
+                .setGeneration(42)
+                .setControllerNumber(43)
+                .setName("Test Device " + DEVICE_ID)
+                .setVendorId(44)
+                .setProductId(45)
+                .setDescriptor("descriptor")
+                .setExternal(true)
+                .setSources(InputDevice.SOURCE_HDMI)
+                .setKeyboardType(InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC)
+                .setKeyCharacterMap(keyCharacterMap)
+                .setHasVibrator(true)
+                .setHasMicrophone(true)
+                .setHasButtonUnderPad(true)
+                .setHasSensor(true)
+                .setHasBattery(true)
+                .setCountryCode(InputDeviceCountryCode.INTERNATIONAL)
+                .build();
 
         Parcel parcel = Parcel.obtain();
         device.writeToParcel(parcel, 0);
diff --git a/tests/TouchLatency/OWNERS b/tests/TouchLatency/OWNERS
new file mode 100644
index 0000000..2b7de25
--- /dev/null
+++ b/tests/TouchLatency/OWNERS
@@ -0,0 +1,2 @@
+include platform/frameworks/base:/graphics/java/android/graphics/OWNERS
+include platform/frameworks/native:/services/surfaceflinger/OWNERS
\ No newline at end of file
diff --git a/tests/TouchLatency/app/build.gradle b/tests/TouchLatency/app/build.gradle
index 04a8788..f5ae6f4 100644
--- a/tests/TouchLatency/app/build.gradle
+++ b/tests/TouchLatency/app/build.gradle
@@ -1,13 +1,13 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 33
     buildToolsVersion '28.0.3'
 
     defaultConfig {
         applicationId "com.prefabulated.touchlatency"
         minSdkVersion 28
-        targetSdkVersion 28
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
     }
diff --git a/tests/TouchLatency/app/src/main/AndroidManifest.xml b/tests/TouchLatency/app/src/main/AndroidManifest.xml
index 9894736..25bb5d9 100644
--- a/tests/TouchLatency/app/src/main/AndroidManifest.xml
+++ b/tests/TouchLatency/app/src/main/AndroidManifest.xml
@@ -20,16 +20,22 @@
     <application android:allowBackup="true"
          android:icon="@mipmap/ic_launcher"
          android:label="@string/app_name"
-         android:theme="@style/AppTheme">
+         android:theme="@style/AppTheme"
+        android:resizeableActivity="true" >
         <activity android:name=".TouchLatencyActivity"
              android:label="@string/app_name"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
-
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+
+        <activity android:name=".TouchLatencyActivityPresentation"
+            android:label="@string/app_name"
+            android:parentActivityName=".TouchLatencyActivity"
+            android:exported="true">
+        </activity>
     </application>
 
 </manifest>
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
index a2842b6..6ab3b3e 100644
--- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
@@ -17,218 +17,40 @@
 package com.prefabulated.touchlatency;
 
 import android.app.Activity;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Trace;
-import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Display;
 import android.view.Display.Mode;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 
-import java.math.RoundingMode;
-import java.text.DecimalFormat;
-
-class TouchLatencyView extends View implements View.OnTouchListener {
-    private static final String LOG_TAG = "TouchLatency";
-    private static final int BACKGROUND_COLOR = 0xFF400080;
-    private static final int INNER_RADIUS = 70;
-    private static final int BALL_DIAMETER = 200;
-    private static final int SEC_TO_NANOS = 1000000000;
-    private static final float FPS_UPDATE_THRESHOLD = 20;
-    private static final long BALL_VELOCITY = 420;
-
-    public TouchLatencyView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        Trace.beginSection("TouchLatencyView constructor");
-        setOnTouchListener(this);
-        setWillNotDraw(false);
-        mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBluePaint.setColor(0xFF0000FF);
-        mBluePaint.setStyle(Paint.Style.FILL);
-        mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mGreenPaint.setColor(0xFF00FF00);
-        mGreenPaint.setStyle(Paint.Style.FILL);
-        mYellowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mYellowPaint.setColor(0xFFFFFF00);
-        mYellowPaint.setStyle(Paint.Style.FILL);
-        mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mRedPaint.setColor(0xFFFF0000);
-        mRedPaint.setStyle(Paint.Style.FILL);
-        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mTextPaint.setColor(0xFFFFFFFF);
-        mTextPaint.setTextSize(100);
-        mTextPaint.setTextAlign(Align.RIGHT);
-
-        mTouching = false;
-
-        mLastDrawNano = 0;
-        mFps = 0;
-        mLastFpsUpdate = 0;
-        mFrameCount = 0;
-
-        mDf = new DecimalFormat("fps: #.##");
-        mDf.setRoundingMode(RoundingMode.HALF_UP);
-
-        Trace.endSection();
-    }
-
-    @Override
-    public boolean onTouch(View view, MotionEvent event) {
-        Trace.beginSection("TouchLatencyView onTouch");
-        int action = event.getActionMasked();
-        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
-            mTouching = true;
-            invalidate();
-
-            mTouchX = event.getX();
-            mTouchY = event.getY();
-        } else if (action == MotionEvent.ACTION_UP) {
-            mTouching = false;
-            invalidate();
-        }
-        Trace.endSection();
-        return true;
-    }
-
-    private void drawTouch(Canvas canvas) {
-        Trace.beginSection("TouchLatencyView drawTouch");
-
-        try {
-            if (!mTouching) {
-                Log.d(LOG_TAG, "Filling background");
-                canvas.drawColor(BACKGROUND_COLOR);
-                return;
-            }
-
-            float deltaX = (mTouchX - mLastDrawnX);
-            float deltaY = (mTouchY - mLastDrawnY);
-            float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
-
-            mLastDrawnX = mTouchX;
-            mLastDrawnY = mTouchY;
-
-            canvas.drawColor(BACKGROUND_COLOR);
-            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
-            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
-            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
-            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
-        } finally {
-            Trace.endSection();
-        }
-    }
-
-    private Paint getBallColor() {
-        if (mFps > 75)
-            return mGreenPaint;
-        else if (mFps > 45)
-            return mYellowPaint;
-        else
-            return mRedPaint;
-    }
-
-    private void drawBall(Canvas canvas) {
-        Trace.beginSection("TouchLatencyView drawBall");
-        int width = canvas.getWidth();
-        int height = canvas.getHeight();
-        float fps = 0f;
-
-        long t = System.nanoTime();
-        long tDiff = t - mLastDrawNano;
-        mLastDrawNano = t;
-        mFrameCount++;
-
-        if (tDiff < SEC_TO_NANOS) {
-            fps = 1f * SEC_TO_NANOS / tDiff;
-        }
-
-        long fDiff = t - mLastFpsUpdate;
-        if (Math.abs(mFps - fps) > FPS_UPDATE_THRESHOLD) {
-            mFps = fps;
-            mLastFpsUpdate = t;
-            mFrameCount = 0;
-        } else if (fDiff > SEC_TO_NANOS) {
-            mFps = 1f * mFrameCount * SEC_TO_NANOS / fDiff;
-            mLastFpsUpdate = t;
-            mFrameCount = 0;
-        }
-
-        final long pos = t * BALL_VELOCITY / SEC_TO_NANOS;
-        final long xMax = width - BALL_DIAMETER;
-        final long yMax = height - BALL_DIAMETER;
-        long xOffset = pos % xMax;
-        long yOffset = pos % yMax;
-
-        float left, right, top, bottom;
-
-        if (((pos / xMax) & 1) == 0) {
-            left = xMax - xOffset;
-        } else {
-            left = xOffset;
-        }
-        right = left + BALL_DIAMETER;
-
-        if (((pos / yMax) & 1) == 0) {
-            top = yMax - yOffset;
-        } else {
-            top = yOffset;
-        }
-        bottom = top + BALL_DIAMETER;
-
-        // Draw the ball
-        canvas.drawColor(BACKGROUND_COLOR);
-        canvas.drawOval(left, top, right, bottom, getBallColor());
-        canvas.drawText(mDf.format(mFps), width, 100, mTextPaint);
-
-        invalidate();
-        Trace.endSection();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        Trace.beginSection("TouchLatencyView onDraw");
-        if (mMode == 0) {
-            drawTouch(canvas);
-        } else {
-            drawBall(canvas);
-        }
-        Trace.endSection();
-    }
-
-    public void changeMode(MenuItem item) {
-        Trace.beginSection("TouchLatencyView changeMode");
-        final int NUM_MODES = 2;
-        final String modes[] = {"Touch", "Ball"};
-        mMode = (mMode + 1) % NUM_MODES;
-        invalidate();
-        item.setTitle(modes[mMode]);
-        Trace.endSection();
-    }
-
-    private final Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint, mTextPaint;
-    private int mMode;
-
-    private boolean mTouching;
-    private float mTouchX, mTouchY;
-    private float mLastDrawnX, mLastDrawnY;
-
-    private long mLastDrawNano, mLastFpsUpdate, mFrameCount;
-    private float mFps;
-    private DecimalFormat mDf;
-}
-
 public class TouchLatencyActivity extends Activity {
     private Mode mDisplayModes[];
     private int mCurrentModeIndex;
+    private DisplayManager mDisplayManager;
+    private final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+        @Override
+        public void onDisplayAdded(int i) {
+            invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onDisplayRemoved(int i) {
+            invalidateOptionsMenu();
+        }
+
+        @Override
+        public void onDisplayChanged(int i) {
+            invalidateOptionsMenu();
+        }
+    };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -236,9 +58,9 @@
 
         Trace.beginSection("TouchLatencyActivity onCreate");
         setContentView(R.layout.activity_touch_latency);
-
         mTouchView = findViewById(R.id.canvasView);
 
+        configureDisplayListener();
         WindowManager wm = getWindowManager();
         Display display = wm.getDefaultDisplay();
         mDisplayModes = display.getSupportedModes();
@@ -250,11 +72,9 @@
                 break;
             }
         }
-
         Trace.endSection();
     }
 
-
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         Trace.beginSection("TouchLatencyActivity onCreateOptionsMenu");
@@ -265,17 +85,26 @@
             Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
             updateDisplayMode(menuItem, currentMode);
         }
+        updateMultiDisplayMenu(menu.findItem(R.id.multi_display));
         Trace.endSection();
         return true;
     }
 
-
     private void updateDisplayMode(MenuItem menuItem, Mode displayMode) {
         int fps = (int) displayMode.getRefreshRate();
         menuItem.setTitle(fps + "hz");
         menuItem.setVisible(true);
     }
 
+    private void updateMultiDisplayMenu(MenuItem item) {
+        item.setVisible(mDisplayManager.getDisplays().length > 1);
+    }
+
+    private void configureDisplayListener() {
+        mDisplayManager = getSystemService(DisplayManager.class);
+        mDisplayManager.registerDisplayListener(mDisplayListener, new Handler());
+    }
+
     public void changeDisplayMode(MenuItem item) {
         Window w = getWindow();
         WindowManager.LayoutParams params = w.getAttributes();
@@ -299,6 +128,19 @@
         mCurrentModeIndex = modeIndex;
     }
 
+    private void changeMultipleDisplays() {
+        Intent intent = new Intent(this, TouchLatencyActivityPresentation.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
+        ActivityOptions options = ActivityOptions.makeBasic();
+        for (int i = 1; i < mDisplayManager.getDisplays().length; ++i) {
+            // We assume the first display is already displaying the TouchLatencyActivity
+            int displayId = mDisplayManager.getDisplays()[i].getDisplayId();
+            options.setLaunchDisplayId(displayId);
+            intent.putExtra(TouchLatencyActivityPresentation.DISPLAY_ID, displayId);
+            startActivity(intent, options.toBundle());
+        }
+    }
+
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
@@ -309,15 +151,32 @@
         int id = item.getItemId();
 
         //noinspection SimplifiableIfStatement
-        if (id == R.id.action_settings) {
-            mTouchView.changeMode(item);
-        } else if (id == R.id.display_mode) {
-            changeDisplayMode(item);
+        switch (id) {
+            case R.id.action_settings: {
+                mTouchView.changeMode(item);
+                break;
+            }
+            case R.id.display_mode: {
+                changeDisplayMode(item);
+                break;
+            }
+            case R.id.multi_display: {
+                changeMultipleDisplays();
+                break;
+            }
         }
 
         Trace.endSection();
         return super.onOptionsItemSelected(item);
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mDisplayManager != null) {
+            mDisplayManager.unregisterDisplayListener(mDisplayListener);
+        }
+    }
+
     private TouchLatencyView mTouchView;
 }
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivityPresentation.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivityPresentation.java
new file mode 100644
index 0000000..2602e6b
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivityPresentation.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.prefabulated.touchlatency;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.Display;
+import android.view.Display.Mode;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.Window;
+import android.view.WindowManager;
+
+public class TouchLatencyActivityPresentation extends Activity {
+    public static final String DISPLAY_ID = "DISPLAY_ID";
+    private Mode[] mDisplayModes;
+    private int mCurrentModeIndex;
+    private int mDisplayId;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (getIntent().hasExtra(DISPLAY_ID)) {
+            mDisplayId = (int) getIntent().getExtras().get(DISPLAY_ID);
+        }
+        Trace.beginSection(
+                "TouchLatencyActivityPresentation::DisplayId::" + mDisplayId + " onCreate");
+        setContentView(R.layout.activity_touch_latency);
+
+        mTouchView = findViewById(R.id.canvasView);
+
+        WindowManager wm = getWindowManager();
+        Display display = wm.getDefaultDisplay();
+        mDisplayModes = display.getSupportedModes();
+        Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
+
+        for (int i = 0; i < mDisplayModes.length; i++) {
+            if (currentMode.getModeId() == mDisplayModes[i].getModeId()) {
+                mCurrentModeIndex = i;
+                break;
+            }
+        }
+        Trace.endSection();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        Trace.beginSection(
+                "TouchLatencyActivityPresentation::DisplayId:: "
+                        + mDisplayId + "  onCreateOptionsMenu");
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.menu_touch_latency, menu);
+        if (mDisplayModes.length > 1) {
+            MenuItem menuItem = menu.findItem(R.id.display_mode);
+            Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
+            updateDisplayMode(menuItem, currentMode);
+        }
+        Trace.endSection();
+        return true;
+    }
+
+    private void updateDisplayMode(MenuItem menuItem, Mode displayMode) {
+        int fps = (int) displayMode.getRefreshRate();
+        menuItem.setTitle(fps + "hz");
+        menuItem.setVisible(true);
+    }
+
+    public void changeDisplayMode(MenuItem item) {
+        Window w = getWindow();
+        WindowManager.LayoutParams params = w.getAttributes();
+
+        int modeIndex = (mCurrentModeIndex + 1) % mDisplayModes.length;
+        params.preferredDisplayModeId = mDisplayModes[modeIndex].getModeId();
+        w.setAttributes(params);
+
+        updateDisplayMode(item, mDisplayModes[modeIndex]);
+        mCurrentModeIndex = modeIndex;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        Trace.beginSection(
+                "TouchLatencyActivityPresentation::DisplayId::"
+                        + mDisplayId + "  onOptionsItemSelected");
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+
+        //noinspection SimplifiableIfStatement
+        switch (id) {
+            case R.id.action_settings: {
+                mTouchView.changeMode(item);
+                break;
+            }
+            case R.id.display_mode: {
+                changeDisplayMode(item);
+                break;
+            }
+        }
+
+        Trace.endSection();
+        return super.onOptionsItemSelected(item);
+    }
+
+    private TouchLatencyView mTouchView;
+}
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyView.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyView.java
new file mode 100644
index 0000000..0803e8e
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyView.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.prefabulated.touchlatency;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Trace;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
+
+class TouchLatencyView extends View implements View.OnTouchListener {
+    private static final String LOG_TAG = "TouchLatency";
+    private static final int BACKGROUND_COLOR = 0xFF400080;
+    private static final int INNER_RADIUS = 70;
+    private static final int BALL_DIAMETER = 200;
+    private static final int SEC_TO_NANOS = 1000000000;
+    private static final float FPS_UPDATE_THRESHOLD = 20;
+    private static final long BALL_VELOCITY = 420;
+
+    public TouchLatencyView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        Trace.beginSection("TouchLatencyView constructor");
+        setOnTouchListener(this);
+        setWillNotDraw(false);
+        mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBluePaint.setColor(0xFF0000FF);
+        mBluePaint.setStyle(Paint.Style.FILL);
+        mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mGreenPaint.setColor(0xFF00FF00);
+        mGreenPaint.setStyle(Paint.Style.FILL);
+        mYellowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mYellowPaint.setColor(0xFFFFFF00);
+        mYellowPaint.setStyle(Paint.Style.FILL);
+        mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mRedPaint.setColor(0xFFFF0000);
+        mRedPaint.setStyle(Paint.Style.FILL);
+        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint.setColor(0xFFFFFFFF);
+        mTextPaint.setTextSize(100);
+        mTextPaint.setTextAlign(Paint.Align.RIGHT);
+
+        mTouching = false;
+
+        mLastDrawNano = 0;
+        mFps = 0;
+        mLastFpsUpdate = 0;
+        mFrameCount = 0;
+
+        mDf = new DecimalFormat("fps: #.##");
+        mDf.setRoundingMode(RoundingMode.HALF_UP);
+
+        Trace.endSection();
+    }
+
+    @Override
+    public boolean onTouch(View view, MotionEvent event) {
+        Trace.beginSection("TouchLatencyView onTouch");
+        int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
+            mTouching = true;
+            invalidate();
+
+            mTouchX = event.getX();
+            mTouchY = event.getY();
+        } else if (action == MotionEvent.ACTION_UP) {
+            mTouching = false;
+            invalidate();
+        }
+        Trace.endSection();
+        return true;
+    }
+
+    private void drawTouch(Canvas canvas) {
+        Trace.beginSection("TouchLatencyView drawTouch");
+
+        try {
+            if (!mTouching) {
+                Log.d(LOG_TAG, "Filling background");
+                canvas.drawColor(BACKGROUND_COLOR);
+                return;
+            }
+
+            float deltaX = (mTouchX - mLastDrawnX);
+            float deltaY = (mTouchY - mLastDrawnY);
+            float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
+
+            mLastDrawnX = mTouchX;
+            mLastDrawnY = mTouchY;
+
+            canvas.drawColor(BACKGROUND_COLOR);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
+            canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
+        } finally {
+            Trace.endSection();
+        }
+    }
+
+    private Paint getBallColor() {
+        if (mFps > 75) {
+            return mGreenPaint;
+        } else if (mFps > 45) {
+            return mYellowPaint;
+        } else
+            return mRedPaint;
+    }
+
+    private void drawBall(Canvas canvas) {
+        Trace.beginSection("TouchLatencyView drawBall");
+        int width = canvas.getWidth();
+        int height = canvas.getHeight();
+        float fps = 0f;
+
+        long t = System.nanoTime();
+        long tDiff = t - mLastDrawNano;
+        mLastDrawNano = t;
+        mFrameCount++;
+
+        if (tDiff < SEC_TO_NANOS) {
+            fps = 1f * SEC_TO_NANOS / tDiff;
+        }
+
+        long fDiff = t - mLastFpsUpdate;
+        if (Math.abs(mFps - fps) > FPS_UPDATE_THRESHOLD) {
+            mFps = fps;
+            mLastFpsUpdate = t;
+            mFrameCount = 0;
+        } else if (fDiff > SEC_TO_NANOS) {
+            mFps = 1f * mFrameCount * SEC_TO_NANOS / fDiff;
+            mLastFpsUpdate = t;
+            mFrameCount = 0;
+        }
+
+        final long pos = t * BALL_VELOCITY / SEC_TO_NANOS;
+        final long xMax = width - BALL_DIAMETER;
+        final long yMax = height - BALL_DIAMETER;
+        long xOffset = pos % xMax;
+        long yOffset = pos % yMax;
+
+        float left, right, top, bottom;
+
+        if (((pos / xMax) & 1) == 0) {
+            left = xMax - xOffset;
+        } else {
+            left = xOffset;
+        }
+        right = left + BALL_DIAMETER;
+
+        if (((pos / yMax) & 1) == 0) {
+            top = yMax - yOffset;
+        } else {
+            top = yOffset;
+        }
+        bottom = top + BALL_DIAMETER;
+
+        // Draw the ball
+        canvas.drawColor(BACKGROUND_COLOR);
+        canvas.drawOval(left, top, right, bottom, getBallColor());
+        canvas.drawText(mDf.format(mFps), width, 100, mTextPaint);
+
+        invalidate();
+        Trace.endSection();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        Trace.beginSection("TouchLatencyView onDraw");
+        if (mMode == 0) {
+            drawTouch(canvas);
+        } else {
+            drawBall(canvas);
+        }
+        Trace.endSection();
+    }
+
+    public void changeMode(MenuItem item) {
+        Trace.beginSection("TouchLatencyView changeMode");
+        final int NUM_MODES = 2;
+        final String modes[] = {"Touch", "Ball"};
+        mMode = (mMode + 1) % NUM_MODES;
+        invalidate();
+        item.setTitle(modes[mMode]);
+        Trace.endSection();
+    }
+
+    private final Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint, mTextPaint;
+    private int mMode;
+
+    private boolean mTouching;
+    private float mTouchX, mTouchY;
+    private float mLastDrawnX, mLastDrawnY;
+
+    private long mLastDrawNano, mLastFpsUpdate, mFrameCount;
+    private float mFps;
+    private DecimalFormat mDf;
+}
diff --git a/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml b/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
index 52be919..abc7fd5 100644
--- a/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
+++ b/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
@@ -25,4 +25,10 @@
         android:showAsAction="ifRoom"
         android:title="@string/display_mode"
         android:visible="false"/>
+
+    <item
+        android:id="@+id/multi_display"
+        android:showAsAction="ifRoom"
+        android:title="@string/multi_display"
+        android:visible="false"/>
 </menu>
diff --git a/tests/TouchLatency/app/src/main/res/values/strings.xml b/tests/TouchLatency/app/src/main/res/values/strings.xml
index 771992c..5ee86d8 100644
--- a/tests/TouchLatency/app/src/main/res/values/strings.xml
+++ b/tests/TouchLatency/app/src/main/res/values/strings.xml
@@ -18,4 +18,5 @@
 
     <string name="mode">Touch</string>
     <string name="display_mode">Mode</string>
+    <string name="multi_display">multi-display</string>
 </resources>
diff --git a/tests/TouchLatency/build.gradle b/tests/TouchLatency/build.gradle
index 03abe82..381e55e 100644
--- a/tests/TouchLatency/build.gradle
+++ b/tests/TouchLatency/build.gradle
@@ -6,7 +6,7 @@
         google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.2.1'
+        classpath 'com.android.tools.build:gradle:4.2.2'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
index 2d80b69..4d9ca16 100644
--- a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/tools/codegen/BUILD.bazel b/tools/codegen/BUILD.bazel
new file mode 100644
index 0000000..c14046d
--- /dev/null
+++ b/tools/codegen/BUILD.bazel
@@ -0,0 +1,21 @@
+# TODO(b/245731902): auto-generate these with bp2build.
+load("@rules_kotlin//kotlin:jvm_library.bzl", "kt_jvm_library")
+
+java_binary(
+    name = "codegen_cli",
+    main_class = "com.android.codegen.MainKt",
+    runtime_deps = [
+        ":codegen_cli_kt_lib",
+    ],
+)
+
+kt_jvm_library(
+    name = "codegen_cli_kt_lib",
+    srcs = glob(["src/**/*.kt"]),
+    deps = ["//external/javaparser"],
+)
+
+kt_jvm_library(
+    name = "codegen-version-info",
+    srcs = glob(["src/**/SharedConstants.kt"]),
+)
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
index 12f3a16..8aa3e25 100644
--- a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -40,7 +40,8 @@
         EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
         ManualPermissionCheckDetector.ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION,
         SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
-        PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS
+        PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
+        RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG,
     )
 
     override val api: Int
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
new file mode 100644
index 0000000..c3e0428
--- /dev/null
+++ b/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
@@ -0,0 +1,927 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+import com.android.tools.lint.checks.DataFlowAnalyzer
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.ConstantEvaluator
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.UastLintUtils.Companion.findLastAssignment
+import com.android.tools.lint.detector.api.getMethodName
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiVariable
+import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.UParenthesizedExpression
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.getContainingUMethod
+import org.jetbrains.uast.isNullLiteral
+import org.jetbrains.uast.skipParenthesizedExprDown
+import org.jetbrains.uast.tryResolve
+
+/**
+ * Detector that identifies `registerReceiver()` calls which are missing the `RECEIVER_EXPORTED` or
+ * `RECEIVER_NOT_EXPORTED` flags on T+.
+ *
+ * TODO: Add API level conditions to better support non-platform code.
+ * 1. Check if registerReceiver() call is reachable on T+.
+ * 2. Check if targetSdkVersion is T+.
+ *
+ * eg: isWithinVersionCheckConditional(context, node, 31, false)
+ * eg: isPrecededByVersionCheckExit(context, node, 31) ?
+ */
+@Suppress("UnstableApiUsage")
+class RegisterReceiverFlagDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> = listOf(
+            "registerReceiver",
+            "registerReceiverAsUser",
+            "registerReceiverForAllUsers"
+    )
+
+    private fun checkIsProtectedReceiverAndReturnUnprotectedActions(
+            filterArg: UExpression,
+            node: UCallExpression,
+            evaluator: ConstantEvaluator
+        ): Pair<Boolean, List<String>> { // isProtected, unprotectedActions
+            val actions = mutableSetOf<String>()
+            val construction = findIntentFilterConstruction(filterArg, node)
+
+            if (construction == null) return Pair(false, listOf<String>())
+            val constructorActionArg = construction.getArgumentForParameter(0)
+            (constructorActionArg?.let(evaluator::evaluate) as? String)?.let(actions::add)
+
+            val actionCollectorVisitor =
+                ActionCollectorVisitor(setOf(construction), node, evaluator)
+
+            val parent = node.getContainingUMethod()
+            parent?.accept(actionCollectorVisitor)
+            actions.addAll(actionCollectorVisitor.actions)
+
+            // If we failed to evaluate any actions, there will be a null action in the set.
+            val isProtected =
+              actions.all(PROTECTED_BROADCASTS::contains) &&
+                !actionCollectorVisitor.intentFilterEscapesScope
+            val unprotectedActionsList = actions.filterNot(PROTECTED_BROADCASTS::contains)
+            return Pair(isProtected, unprotectedActionsList)
+        }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (!context.evaluator.isMemberInSubClassOf(method, "android.content.Context")) return
+
+        // The parameter positions vary across the various registerReceiver*() methods, so rather
+        // than hardcode them we simply look them up based on the parameter name and type.
+        val receiverArg =
+            findArgument(node, method, "android.content.BroadcastReceiver", "receiver")
+        val filterArg = findArgument(node, method, "android.content.IntentFilter", "filter")
+        val flagsArg = findArgument(node, method, "int", "flags")
+
+        if (receiverArg == null || receiverArg.isNullLiteral() || filterArg == null) {
+            return
+        }
+
+        val evaluator = ConstantEvaluator().allowFieldInitializers()
+
+        val (isProtected, unprotectedActionsList) =
+          checkIsProtectedReceiverAndReturnUnprotectedActions(filterArg, node, evaluator)
+
+        val flags = evaluator.evaluate(flagsArg) as? Int
+
+        if (!isProtected) {
+            val actionsList = unprotectedActionsList.joinToString(", ", "", "", -1, "")
+            val message = "$receiverArg is missing 'RECEIVED_EXPORTED` or 'RECEIVE_NOT_EXPORTED' " +
+                            "flag for unprotected broadcast(s) registered for $actionsList."
+            if (flagsArg == null) {
+                context.report(
+                  ISSUE_RECEIVER_EXPORTED_FLAG, node, context.getLocation(node), message)
+            } else if (flags != null && (flags and RECEIVER_EXPORTED_FLAG_PRESENT_MASK) == 0) {
+                context.report(
+                  ISSUE_RECEIVER_EXPORTED_FLAG, node, context.getLocation(flagsArg), message)
+            }
+        }
+
+        if (DEBUG) {
+            println(node.asRenderString())
+            println("Unprotected Actions: $unprotectedActionsList")
+            println("Protected: $isProtected")
+            println("Flags: $flags")
+        }
+    }
+
+    /** Finds the first argument of a method that matches the given parameter type and name. */
+    private fun findArgument(
+            node: UCallExpression,
+            method: PsiMethod,
+            type: String,
+            name: String
+    ): UExpression? {
+        val psiParameter = method.parameterList.parameters.firstOrNull {
+            it.type.canonicalText == type && it.name == name
+        } ?: return null
+        val argument = node.getArgumentForParameter(psiParameter.parameterIndex())
+        return argument?.skipParenthesizedExprDown()
+    }
+
+    /**
+     * For the supplied expression (eg. intent filter argument), attempts to find its construction.
+     * This will be an `IntentFilter()` constructor, an `IntentFilter.create()` call, or `null`.
+     */
+    private fun findIntentFilterConstruction(
+            expression: UExpression,
+            node: UCallExpression
+    ): UCallExpression? {
+        val resolved = expression.tryResolve()
+
+        if (resolved is PsiVariable) {
+            val assignment = findLastAssignment(resolved, node) ?: return null
+            return findIntentFilterConstruction(assignment, node)
+        }
+
+        if (expression is UParenthesizedExpression) {
+            return findIntentFilterConstruction(expression.expression, node)
+        }
+
+        if (expression is UQualifiedReferenceExpression) {
+            val call = expression.selector as? UCallExpression ?: return null
+            return if (isReturningContext(call)) {
+                // eg. filter.apply { addAction("abc") } --> use filter variable.
+                findIntentFilterConstruction(expression.receiver, node)
+            } else {
+                // eg. IntentFilter.create("abc") --> use create("abc") UCallExpression.
+                findIntentFilterConstruction(call, node)
+            }
+        }
+
+        val method = resolved as? PsiMethod ?: return null
+        return if (isIntentFilterFactoryMethod(method)) {
+            expression as? UCallExpression
+        } else {
+            null
+        }
+    }
+
+    private fun isIntentFilterFactoryMethod(method: PsiMethod) =
+            (method.containingClass?.qualifiedName == "android.content.IntentFilter" &&
+               (method.returnType?.canonicalText == "android.content.IntentFilter" ||
+                    method.isConstructor))
+
+    /**
+     * Returns true if the given call represents a Kotlin scope function where the return value is
+     * the context object; see https://kotlinlang.org/docs/scope-functions.html#function-selection.
+     */
+    private fun isReturningContext(node: UCallExpression): Boolean {
+        val name = getMethodName(node)
+        if (name == "apply" || name == "also") {
+            return isScopingFunction(node)
+        }
+        return false
+    }
+
+    /**
+     * Returns true if the given node appears to be one of the scope functions. Only checks parent
+     * class; caller should intend that it's actually one of let, with, apply, etc.
+     */
+    private fun isScopingFunction(node: UCallExpression): Boolean {
+        val called = node.resolve() ?: return true
+        // See libraries/stdlib/jvm/build/stdlib-declarations.json
+        return called.containingClass?.qualifiedName == "kotlin.StandardKt__StandardKt"
+    }
+
+    inner class ActionCollectorVisitor(
+        start: Collection<UElement>,
+        val functionCall: UCallExpression,
+        val evaluator: ConstantEvaluator,
+    ) : DataFlowAnalyzer(start) {
+       private var finished = false
+       var intentFilterEscapesScope = false; private set
+       val actions = mutableSetOf<String>()
+
+       override fun argument(call: UCallExpression, reference: UElement) {
+           // TODO: Remove this temporary fix for DataFlowAnalyzer bug (ag/15787550):
+           if (reference !in call.valueArguments) return
+           val methodNames = super@RegisterReceiverFlagDetector.getApplicableMethodNames()
+           when {
+               finished -> return
+               // We've reached the registerReceiver*() call in question.
+               call == functionCall -> finished = true
+               // The filter 'intentFilterEscapesScope' to a method which could modify it.
+               methodNames != null && getMethodName(call)!! !in methodNames ->
+                 intentFilterEscapesScope = true
+           }
+       }
+
+       // Fixed in b/199163915: DataFlowAnalyzer doesn't call this for Kotlin properties.
+       override fun field(field: UElement) {
+           if (!finished) intentFilterEscapesScope = true
+       }
+
+       override fun receiver(call: UCallExpression) {
+           if (!finished && getMethodName(call) == "addAction") {
+               val actionArg = call.getArgumentForParameter(0)
+               if (actionArg != null) {
+                   val action = evaluator.evaluate(actionArg) as? String
+                   if (action != null) actions.add(action)
+               }
+           }
+       }
+    }
+
+    companion object {
+        const val DEBUG = false
+
+        private const val RECEIVER_EXPORTED = 0x2
+        private const val RECEIVER_NOT_EXPORTED = 0x4
+        private const val RECEIVER_EXPORTED_FLAG_PRESENT_MASK =
+          RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED
+
+        @JvmField
+        val ISSUE_RECEIVER_EXPORTED_FLAG: Issue = Issue.create(
+                id = "UnspecifiedRegisterReceiverFlag",
+                briefDescription = "Missing `registerReceiver()` exported flag",
+                explanation = """
+                    Apps targeting Android T (SDK 33) and higher must specify either `RECEIVER_EXPORTED` \
+                    or `RECEIVER_NOT_EXPORTED` when registering a broadcast receiver, unless the \
+                    receiver is only registered for protected system broadcast actions.
+                    """,
+                category = Category.SECURITY,
+                priority = 5,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        RegisterReceiverFlagDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                )
+        )
+
+        val PROTECTED_BROADCASTS = listOf(
+                "android.intent.action.SCREEN_OFF",
+                "android.intent.action.SCREEN_ON",
+                "android.intent.action.USER_PRESENT",
+                "android.intent.action.TIME_SET",
+                "android.intent.action.TIME_TICK",
+                "android.intent.action.TIMEZONE_CHANGED",
+                "android.intent.action.DATE_CHANGED",
+                "android.intent.action.PRE_BOOT_COMPLETED",
+                "android.intent.action.BOOT_COMPLETED",
+                "android.intent.action.PACKAGE_INSTALL",
+                "android.intent.action.PACKAGE_ADDED",
+                "android.intent.action.PACKAGE_REPLACED",
+                "android.intent.action.MY_PACKAGE_REPLACED",
+                "android.intent.action.PACKAGE_REMOVED",
+                "android.intent.action.PACKAGE_REMOVED_INTERNAL",
+                "android.intent.action.PACKAGE_FULLY_REMOVED",
+                "android.intent.action.PACKAGE_CHANGED",
+                "android.intent.action.PACKAGE_FULLY_LOADED",
+                "android.intent.action.PACKAGE_ENABLE_ROLLBACK",
+                "android.intent.action.CANCEL_ENABLE_ROLLBACK",
+                "android.intent.action.ROLLBACK_COMMITTED",
+                "android.intent.action.PACKAGE_RESTARTED",
+                "android.intent.action.PACKAGE_DATA_CLEARED",
+                "android.intent.action.PACKAGE_FIRST_LAUNCH",
+                "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION",
+                "android.intent.action.PACKAGE_NEEDS_VERIFICATION",
+                "android.intent.action.PACKAGE_VERIFIED",
+                "android.intent.action.PACKAGES_SUSPENDED",
+                "android.intent.action.PACKAGES_UNSUSPENDED",
+                "android.intent.action.PACKAGES_SUSPENSION_CHANGED",
+                "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY",
+                "android.intent.action.DISTRACTING_PACKAGES_CHANGED",
+                "android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED",
+                "android.intent.action.UID_REMOVED",
+                "android.intent.action.QUERY_PACKAGE_RESTART",
+                "android.intent.action.CONFIGURATION_CHANGED",
+                "android.intent.action.SPLIT_CONFIGURATION_CHANGED",
+                "android.intent.action.LOCALE_CHANGED",
+                "android.intent.action.APPLICATION_LOCALE_CHANGED",
+                "android.intent.action.BATTERY_CHANGED",
+                "android.intent.action.BATTERY_LEVEL_CHANGED",
+                "android.intent.action.BATTERY_LOW",
+                "android.intent.action.BATTERY_OKAY",
+                "android.intent.action.ACTION_POWER_CONNECTED",
+                "android.intent.action.ACTION_POWER_DISCONNECTED",
+                "android.intent.action.ACTION_SHUTDOWN",
+                "android.intent.action.CHARGING",
+                "android.intent.action.DISCHARGING",
+                "android.intent.action.DEVICE_STORAGE_LOW",
+                "android.intent.action.DEVICE_STORAGE_OK",
+                "android.intent.action.DEVICE_STORAGE_FULL",
+                "android.intent.action.DEVICE_STORAGE_NOT_FULL",
+                "android.intent.action.NEW_OUTGOING_CALL",
+                "android.intent.action.REBOOT",
+                "android.intent.action.DOCK_EVENT",
+                "android.intent.action.THERMAL_EVENT",
+                "android.intent.action.MASTER_CLEAR_NOTIFICATION",
+                "android.intent.action.USER_ADDED",
+                "android.intent.action.USER_REMOVED",
+                "android.intent.action.USER_STARTING",
+                "android.intent.action.USER_STARTED",
+                "android.intent.action.USER_STOPPING",
+                "android.intent.action.USER_STOPPED",
+                "android.intent.action.USER_BACKGROUND",
+                "android.intent.action.USER_FOREGROUND",
+                "android.intent.action.USER_SWITCHED",
+                "android.intent.action.USER_INITIALIZE",
+                "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION",
+                "android.intent.action.DOMAINS_NEED_VERIFICATION",
+                "android.intent.action.OVERLAY_ADDED",
+                "android.intent.action.OVERLAY_CHANGED",
+                "android.intent.action.OVERLAY_REMOVED",
+                "android.intent.action.OVERLAY_PRIORITY_CHANGED",
+                "android.intent.action.MY_PACKAGE_SUSPENDED",
+                "android.intent.action.MY_PACKAGE_UNSUSPENDED",
+                "android.os.action.POWER_SAVE_MODE_CHANGED",
+                "android.os.action.DEVICE_IDLE_MODE_CHANGED",
+                "android.os.action.POWER_SAVE_WHITELIST_CHANGED",
+                "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED",
+                "android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL",
+                "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED",
+                "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED",
+                "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED",
+                "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL",
+                "android.app.action.ENTER_CAR_MODE",
+                "android.app.action.EXIT_CAR_MODE",
+                "android.app.action.ENTER_CAR_MODE_PRIORITIZED",
+                "android.app.action.EXIT_CAR_MODE_PRIORITIZED",
+                "android.app.action.ENTER_DESK_MODE",
+                "android.app.action.EXIT_DESK_MODE",
+                "android.app.action.NEXT_ALARM_CLOCK_CHANGED",
+                "android.app.action.USER_ADDED",
+                "android.app.action.USER_REMOVED",
+                "android.app.action.USER_STARTED",
+                "android.app.action.USER_STOPPED",
+                "android.app.action.USER_SWITCHED",
+                "android.app.action.BUGREPORT_SHARING_DECLINED",
+                "android.app.action.BUGREPORT_FAILED",
+                "android.app.action.BUGREPORT_SHARE",
+                "android.app.action.SHOW_DEVICE_MONITORING_DIALOG",
+                "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED",
+                "android.intent.action.INCIDENT_REPORT_READY",
+                "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS",
+                "android.appwidget.action.APPWIDGET_DELETED",
+                "android.appwidget.action.APPWIDGET_DISABLED",
+                "android.appwidget.action.APPWIDGET_ENABLED",
+                "android.appwidget.action.APPWIDGET_HOST_RESTORED",
+                "android.appwidget.action.APPWIDGET_RESTORED",
+                "android.appwidget.action.APPWIDGET_ENABLE_AND_UPDATE",
+                "android.os.action.SETTING_RESTORED",
+                "android.app.backup.intent.CLEAR",
+                "android.app.backup.intent.INIT",
+                "android.bluetooth.intent.DISCOVERABLE_TIMEOUT",
+                "android.bluetooth.adapter.action.STATE_CHANGED",
+                "android.bluetooth.adapter.action.SCAN_MODE_CHANGED",
+                "android.bluetooth.adapter.action.DISCOVERY_STARTED",
+                "android.bluetooth.adapter.action.DISCOVERY_FINISHED",
+                "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED",
+                "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED",
+                "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.device.action.UUID",
+                "android.bluetooth.device.action.MAS_INSTANCE",
+                "android.bluetooth.device.action.ALIAS_CHANGED",
+                "android.bluetooth.device.action.FOUND",
+                "android.bluetooth.device.action.CLASS_CHANGED",
+                "android.bluetooth.device.action.ACL_CONNECTED",
+                "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED",
+                "android.bluetooth.device.action.ACL_DISCONNECTED",
+                "android.bluetooth.device.action.NAME_CHANGED",
+                "android.bluetooth.device.action.BOND_STATE_CHANGED",
+                "android.bluetooth.device.action.NAME_FAILED",
+                "android.bluetooth.device.action.PAIRING_REQUEST",
+                "android.bluetooth.device.action.PAIRING_CANCEL",
+                "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY",
+                "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL",
+                "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST",
+                "android.bluetooth.device.action.SDP_RECORD",
+                "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED",
+                "android.bluetooth.devicepicker.action.LAUNCH",
+                "android.bluetooth.devicepicker.action.DEVICE_SELECTED",
+                "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED",
+                "android.bluetooth.action.CSIS_DEVICE_AVAILABLE",
+                "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE",
+                "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED",
+                "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_CONF_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED",
+                "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED",
+                "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED",
+                "android.btopp.intent.action.INCOMING_FILE_NOTIFICATION",
+                "android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT",
+                "android.btopp.intent.action.LIST",
+                "android.btopp.intent.action.OPEN_OUTBOUND",
+                "android.btopp.intent.action.HIDE_COMPLETE",
+                "android.btopp.intent.action.CONFIRM",
+                "android.btopp.intent.action.HIDE",
+                "android.btopp.intent.action.RETRY",
+                "android.btopp.intent.action.OPEN",
+                "android.btopp.intent.action.OPEN_INBOUND",
+                "android.btopp.intent.action.TRANSFER_COMPLETE",
+                "android.btopp.intent.action.ACCEPT",
+                "android.btopp.intent.action.DECLINE",
+                "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN",
+                "com.android.bluetooth.pbap.authchall",
+                "com.android.bluetooth.pbap.userconfirmtimeout",
+                "com.android.bluetooth.pbap.authresponse",
+                "com.android.bluetooth.pbap.authcancelled",
+                "com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT",
+                "com.android.bluetooth.sap.action.DISCONNECT_ACTION",
+                "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED",
+                "android.hardware.usb.action.USB_STATE",
+                "android.hardware.usb.action.USB_PORT_CHANGED",
+                "android.hardware.usb.action.USB_ACCESSORY_ATTACHED",
+                "android.hardware.usb.action.USB_ACCESSORY_DETACHED",
+                "android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE",
+                "android.hardware.usb.action.USB_DEVICE_ATTACHED",
+                "android.hardware.usb.action.USB_DEVICE_DETACHED",
+                "android.intent.action.HEADSET_PLUG",
+                "android.media.action.HDMI_AUDIO_PLUG",
+                "android.media.action.MICROPHONE_MUTE_CHANGED",
+                "android.media.action.SPEAKERPHONE_STATE_CHANGED",
+                "android.media.AUDIO_BECOMING_NOISY",
+                "android.media.RINGER_MODE_CHANGED",
+                "android.media.VIBRATE_SETTING_CHANGED",
+                "android.media.VOLUME_CHANGED_ACTION",
+                "android.media.MASTER_VOLUME_CHANGED_ACTION",
+                "android.media.MASTER_MUTE_CHANGED_ACTION",
+                "android.media.MASTER_MONO_CHANGED_ACTION",
+                "android.media.MASTER_BALANCE_CHANGED_ACTION",
+                "android.media.SCO_AUDIO_STATE_CHANGED",
+                "android.media.ACTION_SCO_AUDIO_STATE_UPDATED",
+                "android.intent.action.MEDIA_REMOVED",
+                "android.intent.action.MEDIA_UNMOUNTED",
+                "android.intent.action.MEDIA_CHECKING",
+                "android.intent.action.MEDIA_NOFS",
+                "android.intent.action.MEDIA_MOUNTED",
+                "android.intent.action.MEDIA_SHARED",
+                "android.intent.action.MEDIA_UNSHARED",
+                "android.intent.action.MEDIA_BAD_REMOVAL",
+                "android.intent.action.MEDIA_UNMOUNTABLE",
+                "android.intent.action.MEDIA_EJECT",
+                "android.net.conn.CAPTIVE_PORTAL",
+                "android.net.conn.CONNECTIVITY_CHANGE",
+                "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE",
+                "android.net.conn.DATA_ACTIVITY_CHANGE",
+                "android.net.conn.RESTRICT_BACKGROUND_CHANGED",
+                "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED",
+                "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED",
+                "android.net.nsd.STATE_CHANGED",
+                "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED",
+                "android.nfc.action.ADAPTER_STATE_CHANGED",
+                "android.nfc.action.PREFERRED_PAYMENT_CHANGED",
+                "android.nfc.action.TRANSACTION_DETECTED",
+                "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC",
+                "com.android.nfc.action.LLCP_UP",
+                "com.android.nfc.action.LLCP_DOWN",
+                "com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG",
+                "com.android.nfc.handover.action.ALLOW_CONNECT",
+                "com.android.nfc.handover.action.DENY_CONNECT",
+                "com.android.nfc.handover.action.TIMEOUT_CONNECT",
+                "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED",
+                "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED",
+                "com.android.nfc_extras.action.AID_SELECTED",
+                "android.btopp.intent.action.WHITELIST_DEVICE",
+                "android.btopp.intent.action.STOP_HANDOVER_TRANSFER",
+                "android.nfc.handover.intent.action.HANDOVER_SEND",
+                "android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE",
+                "com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER",
+                "android.net.action.CLEAR_DNS_CACHE",
+                "android.intent.action.PROXY_CHANGE",
+                "android.os.UpdateLock.UPDATE_LOCK_CHANGED",
+                "android.intent.action.DREAMING_STARTED",
+                "android.intent.action.DREAMING_STOPPED",
+                "android.intent.action.ANY_DATA_STATE",
+                "com.android.server.stats.action.TRIGGER_COLLECTION",
+                "com.android.server.WifiManager.action.START_SCAN",
+                "com.android.server.WifiManager.action.START_PNO",
+                "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP",
+                "com.android.server.WifiManager.action.DEVICE_IDLE",
+                "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED",
+                "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED",
+                "com.android.internal.action.EUICC_FACTORY_RESET",
+                "com.android.server.usb.ACTION_OPEN_IN_APPS",
+                "com.android.server.am.DELETE_DUMPHEAP",
+                "com.android.server.net.action.SNOOZE_WARNING",
+                "com.android.server.net.action.SNOOZE_RAPID",
+                "com.android.server.wifi.ACTION_SHOW_SET_RANDOMIZATION_DETAILS",
+                "com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_APP",
+                "com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_APP",
+                "com.android.server.wifi.action.NetworkSuggestion.USER_DISMISSED",
+                "com.android.server.wifi.action.CarrierNetwork.USER_ALLOWED_CARRIER",
+                "com.android.server.wifi.action.CarrierNetwork.USER_DISALLOWED_CARRIER",
+                "com.android.server.wifi.action.CarrierNetwork.USER_DISMISSED",
+                "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION",
+                "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK",
+                "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK",
+                "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE",
+                "com.android.server.wifi.wakeup.DISMISS_NOTIFICATION",
+                "com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES",
+                "com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS",
+                "com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE",
+                "android.net.wifi.WIFI_STATE_CHANGED",
+                "android.net.wifi.WIFI_AP_STATE_CHANGED",
+                "android.net.wifi.WIFI_CREDENTIAL_CHANGED",
+                "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED",
+                "android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED",
+                "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED",
+                "android.net.wifi.SCAN_RESULTS",
+                "android.net.wifi.RSSI_CHANGED",
+                "android.net.wifi.STATE_CHANGE",
+                "android.net.wifi.LINK_CONFIGURATION_CHANGED",
+                "android.net.wifi.CONFIGURED_NETWORKS_CHANGE",
+                "android.net.wifi.action.NETWORK_SETTINGS_RESET",
+                "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT",
+                "android.net.wifi.action.PASSPOINT_ICON",
+                "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST",
+                "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION",
+                "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW",
+                "android.net.wifi.action.REFRESH_USER_PROVISIONING",
+                "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION",
+                "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED",
+                "android.net.wifi.supplicant.CONNECTION_CHANGE",
+                "android.net.wifi.supplicant.STATE_CHANGE",
+                "android.net.wifi.p2p.STATE_CHANGED",
+                "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE",
+                "android.net.wifi.p2p.THIS_DEVICE_CHANGED",
+                "android.net.wifi.p2p.PEERS_CHANGED",
+                "android.net.wifi.p2p.CONNECTION_STATE_CHANGE",
+                "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED",
+                "android.net.conn.TETHER_STATE_CHANGED",
+                "android.net.conn.INET_CONDITION_ACTION",
+                "android.net.conn.NETWORK_CONDITIONS_MEASURED",
+                "android.net.scoring.SCORE_NETWORKS",
+                "android.net.scoring.SCORER_CHANGED",
+                "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE",
+                "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE",
+                "android.intent.action.AIRPLANE_MODE",
+                "android.intent.action.ADVANCED_SETTINGS",
+                "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED",
+                "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES",
+                "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT",
+                "com.android.server.adb.WIRELESS_DEBUG_STATUS",
+                "android.intent.action.ACTION_IDLE_MAINTENANCE_START",
+                "android.intent.action.ACTION_IDLE_MAINTENANCE_END",
+                "com.android.server.ACTION_TRIGGER_IDLE",
+                "android.intent.action.HDMI_PLUGGED",
+                "android.intent.action.PHONE_STATE",
+                "android.intent.action.SUB_DEFAULT_CHANGED",
+                "android.location.PROVIDERS_CHANGED",
+                "android.location.MODE_CHANGED",
+                "android.location.action.GNSS_CAPABILITIES_CHANGED",
+                "android.net.proxy.PAC_REFRESH",
+                "android.telecom.action.DEFAULT_DIALER_CHANGED",
+                "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED",
+                "android.provider.action.SMS_MMS_DB_CREATED",
+                "android.provider.action.SMS_MMS_DB_LOST",
+                "android.intent.action.CONTENT_CHANGED",
+                "android.provider.Telephony.MMS_DOWNLOADED",
+                "android.content.action.PERMISSION_RESPONSE_RECEIVED",
+                "android.content.action.REQUEST_PERMISSION",
+                "android.nfc.handover.intent.action.HANDOVER_STARTED",
+                "android.nfc.handover.intent.action.TRANSFER_DONE",
+                "android.nfc.handover.intent.action.TRANSFER_PROGRESS",
+                "android.nfc.handover.intent.action.TRANSFER_DONE",
+                "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED",
+                "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED",
+                "android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE",
+                "android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED",
+                "android.internal.policy.action.BURN_IN_PROTECTION",
+                "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED",
+                "android.app.action.RESET_PROTECTION_POLICY_CHANGED",
+                "android.app.action.DEVICE_OWNER_CHANGED",
+                "android.app.action.MANAGED_USER_CREATED",
+                "android.intent.action.ANR",
+                "android.intent.action.CALL",
+                "android.intent.action.CALL_PRIVILEGED",
+                "android.intent.action.DROPBOX_ENTRY_ADDED",
+                "android.intent.action.INPUT_METHOD_CHANGED",
+                "android.intent.action.internal_sim_state_changed",
+                "android.intent.action.LOCKED_BOOT_COMPLETED",
+                "android.intent.action.PRECISE_CALL_STATE",
+                "android.intent.action.SUBSCRIPTION_PHONE_STATE",
+                "android.intent.action.USER_INFO_CHANGED",
+                "android.intent.action.USER_UNLOCKED",
+                "android.intent.action.WALLPAPER_CHANGED",
+                "android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED",
+                "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS",
+                "android.app.action.DEVICE_ADMIN_DISABLED",
+                "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED",
+                "android.app.action.DEVICE_ADMIN_ENABLED",
+                "android.app.action.LOCK_TASK_ENTERING",
+                "android.app.action.LOCK_TASK_EXITING",
+                "android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE",
+                "android.app.action.ACTION_PASSWORD_CHANGED",
+                "android.app.action.ACTION_PASSWORD_EXPIRING",
+                "android.app.action.ACTION_PASSWORD_FAILED",
+                "android.app.action.ACTION_PASSWORD_SUCCEEDED",
+                "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION",
+                "com.android.server.ACTION_PROFILE_OFF_DEADLINE",
+                "com.android.server.ACTION_TURN_PROFILE_ON_NOTIFICATION",
+                "android.intent.action.MANAGED_PROFILE_ADDED",
+                "android.intent.action.MANAGED_PROFILE_UNLOCKED",
+                "android.intent.action.MANAGED_PROFILE_REMOVED",
+                "android.app.action.MANAGED_PROFILE_PROVISIONED",
+                "android.bluetooth.adapter.action.BLE_STATE_CHANGED",
+                "com.android.bluetooth.map.USER_CONFIRM_TIMEOUT",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY",
+                "android.content.jobscheduler.JOB_DELAY_EXPIRED",
+                "android.content.syncmanager.SYNC_ALARM",
+                "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION",
+                "android.media.STREAM_DEVICES_CHANGED_ACTION",
+                "android.media.STREAM_MUTE_CHANGED_ACTION",
+                "android.net.sip.SIP_SERVICE_UP",
+                "android.nfc.action.ADAPTER_STATE_CHANGED",
+                "android.os.action.CHARGING",
+                "android.os.action.DISCHARGING",
+                "android.search.action.SEARCHABLES_CHANGED",
+                "android.security.STORAGE_CHANGED",
+                "android.security.action.TRUST_STORE_CHANGED",
+                "android.security.action.KEYCHAIN_CHANGED",
+                "android.security.action.KEY_ACCESS_CHANGED",
+                "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED",
+                "android.telecom.action.PHONE_ACCOUNT_REGISTERED",
+                "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED",
+                "android.telecom.action.POST_CALL",
+                "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION",
+                "android.telephony.action.CARRIER_CONFIG_CHANGED",
+                "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED",
+                "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED",
+                "android.telephony.action.SECRET_CODE",
+                "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION",
+                "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED",
+                "com.android.bluetooth.btservice.action.ALARM_WAKEUP",
+                "com.android.server.action.NETWORK_STATS_POLL",
+                "com.android.server.action.NETWORK_STATS_UPDATED",
+                "com.android.server.timedetector.NetworkTimeUpdateService.action.POLL",
+                "com.android.server.telecom.intent.action.CALLS_ADD_ENTRY",
+                "com.android.settings.location.MODE_CHANGING",
+                "com.android.settings.bluetooth.ACTION_DISMISS_PAIRING",
+                "com.android.settings.network.DELETE_SUBSCRIPTION",
+                "com.android.settings.network.SWITCH_TO_SUBSCRIPTION",
+                "com.android.settings.wifi.action.NETWORK_REQUEST",
+                "NotificationManagerService.TIMEOUT",
+                "NotificationHistoryDatabase.CLEANUP",
+                "ScheduleConditionProvider.EVALUATE",
+                "EventConditionProvider.EVALUATE",
+                "SnoozeHelper.EVALUATE",
+                "wifi_scan_available",
+                "action.cne.started",
+                "android.content.jobscheduler.JOB_DEADLINE_EXPIRED",
+                "android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW",
+                "android.net.conn.CONNECTIVITY_CHANGE_SUPL",
+                "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED",
+                "android.os.storage.action.VOLUME_STATE_CHANGED",
+                "android.os.storage.action.DISK_SCANNED",
+                "com.android.server.action.UPDATE_TWILIGHT_STATE",
+                "com.android.server.action.RESET_TWILIGHT_AUTO",
+                "com.android.server.device_idle.STEP_IDLE_STATE",
+                "com.android.server.device_idle.STEP_LIGHT_IDLE_STATE",
+                "com.android.server.Wifi.action.TOGGLE_PNO",
+                "intent.action.ACTION_RF_BAND_INFO",
+                "android.intent.action.MEDIA_RESOURCE_GRANTED",
+                "android.app.action.NETWORK_LOGS_AVAILABLE",
+                "android.app.action.SECURITY_LOGS_AVAILABLE",
+                "android.app.action.COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED",
+                "android.app.action.INTERRUPTION_FILTER_CHANGED",
+                "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL",
+                "android.app.action.NOTIFICATION_POLICY_CHANGED",
+                "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED",
+                "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED",
+                "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED",
+                "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED",
+                "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED",
+                "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED",
+                "android.app.action.APP_BLOCK_STATE_CHANGED",
+                "android.permission.GET_APP_GRANTED_URI_PERMISSIONS",
+                "android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS",
+                "android.intent.action.DYNAMIC_SENSOR_CHANGED",
+                "android.accounts.LOGIN_ACCOUNTS_CHANGED",
+                "android.accounts.action.ACCOUNT_REMOVED",
+                "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED",
+                "com.android.sync.SYNC_CONN_STATUS_CHANGED",
+                "android.net.sip.action.SIP_INCOMING_CALL",
+                "com.android.phone.SIP_ADD_PHONE",
+                "android.net.sip.action.SIP_REMOVE_PROFILE",
+                "android.net.sip.action.SIP_SERVICE_UP",
+                "android.net.sip.action.SIP_CALL_OPTION_CHANGED",
+                "android.net.sip.action.START_SIP",
+                "android.bluetooth.adapter.action.BLE_ACL_CONNECTED",
+                "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED",
+                "android.bluetooth.input.profile.action.HANDSHAKE",
+                "android.bluetooth.input.profile.action.REPORT",
+                "android.intent.action.TWILIGHT_CHANGED",
+                "com.android.server.fingerprint.ACTION_LOCKOUT_RESET",
+                "android.net.wifi.PASSPOINT_ICON_RECEIVED",
+                "com.android.server.notification.CountdownConditionProvider",
+                "android.server.notification.action.ENABLE_NAS",
+                "android.server.notification.action.DISABLE_NAS",
+                "android.server.notification.action.LEARNMORE_NAS",
+                "com.android.internal.location.ALARM_WAKEUP",
+                "com.android.internal.location.ALARM_TIMEOUT",
+                "android.intent.action.GLOBAL_BUTTON",
+                "android.intent.action.MANAGED_PROFILE_AVAILABLE",
+                "android.intent.action.MANAGED_PROFILE_UNAVAILABLE",
+                "com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK",
+                "android.intent.action.PROFILE_ACCESSIBLE",
+                "android.intent.action.PROFILE_INACCESSIBLE",
+                "com.android.server.retaildemo.ACTION_RESET_DEMO",
+                "android.intent.action.DEVICE_LOCKED_CHANGED",
+                "com.android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED",
+                "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED",
+                "com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION",
+                "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED",
+                "android.content.pm.action.SESSION_COMMITTED",
+                "android.os.action.USER_RESTRICTIONS_CHANGED",
+                "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT",
+                "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED",
+                "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED",
+                "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED",
+                "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER",
+                "com.android.intent.action.timezone.RULES_UPDATE_OPERATION",
+                "com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK",
+                "android.intent.action.GET_RESTRICTION_ENTRIES",
+                "android.telephony.euicc.action.OTA_STATUS_CHANGED",
+                "android.app.action.PROFILE_OWNER_CHANGED",
+                "android.app.action.TRANSFER_OWNERSHIP_COMPLETE",
+                "android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE",
+                "android.app.action.STATSD_STARTED",
+                "com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET",
+                "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET",
+                "android.intent.action.DOCK_IDLE",
+                "android.intent.action.DOCK_ACTIVE",
+                "android.content.pm.action.SESSION_UPDATED",
+                "android.settings.action.GRAYSCALE_CHANGED",
+                "com.android.server.jobscheduler.GARAGE_MODE_ON",
+                "com.android.server.jobscheduler.GARAGE_MODE_OFF",
+                "com.android.server.jobscheduler.FORCE_IDLE",
+                "com.android.server.jobscheduler.UNFORCE_IDLE",
+                "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL",
+                "android.intent.action.DEVICE_CUSTOMIZATION_READY",
+                "android.app.action.RESET_PROTECTION_POLICY_CHANGED",
+                "com.android.internal.intent.action.BUGREPORT_REQUESTED",
+                "android.scheduling.action.REBOOT_READY",
+                "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED",
+                "android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED",
+                "android.app.action.SHOW_NEW_USER_DISCLAIMER",
+                "android.telecom.action.CURRENT_TTY_MODE_CHANGED",
+                "android.intent.action.SERVICE_STATE",
+                "android.intent.action.RADIO_TECHNOLOGY",
+                "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED",
+                "android.intent.action.EMERGENCY_CALL_STATE_CHANGED",
+                "android.intent.action.SIG_STR",
+                "android.intent.action.ANY_DATA_STATE",
+                "android.intent.action.DATA_STALL_DETECTED",
+                "android.intent.action.SIM_STATE_CHANGED",
+                "android.intent.action.USER_ACTIVITY_NOTIFICATION",
+                "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS",
+                "android.intent.action.ACTION_MDN_STATE_CHANGED",
+                "android.telephony.action.SERVICE_PROVIDERS_UPDATED",
+                "android.provider.Telephony.SIM_FULL",
+                "com.android.internal.telephony.carrier_key_download_alarm",
+                "com.android.internal.telephony.data-restart-trysetup",
+                "com.android.internal.telephony.data-stall",
+                "com.android.internal.telephony.provisioning_apn_alarm",
+                "android.intent.action.DATA_SMS_RECEIVED",
+                "android.provider.Telephony.SMS_RECEIVED",
+                "android.provider.Telephony.SMS_DELIVER",
+                "android.provider.Telephony.SMS_REJECTED",
+                "android.provider.Telephony.WAP_PUSH_DELIVER",
+                "android.provider.Telephony.WAP_PUSH_RECEIVED",
+                "android.provider.Telephony.SMS_CB_RECEIVED",
+                "android.provider.action.SMS_EMERGENCY_CB_RECEIVED",
+                "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED",
+                "android.provider.Telephony.SECRET_CODE",
+                "com.android.internal.stk.command",
+                "com.android.internal.stk.session_end",
+                "com.android.internal.stk.icc_status_change",
+                "com.android.internal.stk.alpha_notify",
+                "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED",
+                "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED",
+                "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE",
+                "com.android.internal.telephony.CARRIER_SIGNAL_RESET",
+                "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE",
+                "com.android.internal.telephony.PROVISION",
+                "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED",
+                "com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED",
+                "com.android.intent.isim_refresh",
+                "com.android.ims.ACTION_RCS_SERVICE_AVAILABLE",
+                "com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE",
+                "com.android.ims.ACTION_RCS_SERVICE_DIED",
+                "com.android.ims.ACTION_PRESENCE_CHANGED",
+                "com.android.ims.ACTION_PUBLISH_STATUS_CHANGED",
+                "com.android.ims.IMS_SERVICE_UP",
+                "com.android.ims.IMS_SERVICE_DOWN",
+                "com.android.ims.IMS_INCOMING_CALL",
+                "com.android.ims.internal.uce.UCE_SERVICE_UP",
+                "com.android.ims.internal.uce.UCE_SERVICE_DOWN",
+                "com.android.imsconnection.DISCONNECTED",
+                "com.android.intent.action.IMS_FEATURE_CHANGED",
+                "com.android.intent.action.IMS_CONFIG_CHANGED",
+                "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR",
+                "com.android.phone.vvm.omtp.sms.REQUEST_SENT",
+                "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT",
+                "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED",
+                "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO",
+                "com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD",
+                "com.android.internal.telephony.action.COUNTRY_OVERRIDE",
+                "com.android.internal.telephony.OPEN_DEFAULT_SMS_APP",
+                "com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID",
+                "android.telephony.action.SIM_CARD_STATE_CHANGED",
+                "android.telephony.action.SIM_APPLICATION_STATE_CHANGED",
+                "android.telephony.action.SIM_SLOT_STATUS_CHANGED",
+                "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED",
+                "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED",
+                "android.telephony.action.TOGGLE_PROVISION",
+                "android.telephony.action.NETWORK_COUNTRY_CHANGED",
+                "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED",
+                "android.telephony.action.MULTI_SIM_CONFIG_CHANGED",
+                "android.telephony.action.CARRIER_SIGNAL_RESET",
+                "android.telephony.action.CARRIER_SIGNAL_PCO_VALUE",
+                "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE",
+                "android.telephony.action.CARRIER_SIGNAL_REDIRECTED",
+                "android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED",
+                "com.android.phone.settings.CARRIER_PROVISIONING",
+                "com.android.phone.settings.TRIGGER_CARRIER_PROVISIONING",
+                "com.android.internal.telephony.ACTION_VOWIFI_ENABLED",
+                "android.telephony.action.ANOMALY_REPORTED",
+                "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED",
+                "android.intent.action.ACTION_MANAGED_ROAMING_IND",
+                "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE",
+                "android.safetycenter.action.REFRESH_SAFETY_SOURCES",
+                "android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED",
+                "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED",
+                "android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER",
+                "android.service.autofill.action.DELAYED_FILL",
+                "android.app.action.PROVISIONING_COMPLETED",
+                "android.app.action.LOST_MODE_LOCATION_UPDATE",
+                "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED",
+                "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT",
+                "android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED",
+                "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.AG_EVENT",
+                "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED",
+                "android.bluetooth.headsetclient.profile.action.RESULT",
+                "android.bluetooth.headsetclient.profile.action.LAST_VTAG",
+                "android.bluetooth.headsetclient.profile.action.NETWORK_SERVICE_STATE_CHANGED",
+                "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED",
+                "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED",
+                "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED",
+                "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED",
+                "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED",
+                "android.bluetooth.avrcp-controller.profile.action.BROWSE_CONNECTION_STATE_CHANGED",
+                "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.avrcp-controller.profile.action.FOLDER_LIST",
+                "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT",
+                "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED",
+                "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED",
+                "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS",
+                "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT",
+                "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY",
+                "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED",
+                "android.bluetooth.action.TETHERING_STATE_CHANGED",
+                "com.android.internal.action.EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS",
+                "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED",
+                "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION",
+                "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"
+        )
+    }
+}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
new file mode 100644
index 0000000..b76342a
--- /dev/null
+++ b/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.lint
+
+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 RegisterReceiverFlagDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = RegisterReceiverFlagDetector()
+
+    override fun getIssues(): List<Issue> = listOf(
+            RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG
+    )
+
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    fun testProtectedBroadcast() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testProtectedBroadcastCreate() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter =
+                                    IntentFilter.create(Intent.ACTION_BATTERY_CHANGED, "foo/bar");
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testMultipleProtectedBroadcasts() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            filter.addAction(Intent.ACTION_BATTERY_LOW);
+                            filter.addAction(Intent.ACTION_BATTERY_OKAY);
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testSubsequentFilterModification() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            filter.addAction(Intent.ACTION_BATTERY_LOW);
+                            filter.addAction(Intent.ACTION_BATTERY_OKAY);
+                            context.registerReceiver(receiver, filter);
+                            filter.addAction("querty");
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:13: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testNullReceiver() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(null, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testExportedFlagPresent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testNotExportedFlagPresent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter,
+                                    Context.RECEIVER_NOT_EXPORTED);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testFlagArgumentAbsent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testExportedFlagsAbsent() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            context.registerReceiver(receiver, filter, 0);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter, 0);
+                                                                   ~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testExportedFlagVariable() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter("qwerty");
+                            var flags = Context.RECEIVER_EXPORTED;
+                            context.registerReceiver(receiver, filter, flags);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testUnknownFilter() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver,
+                                IntentFilter filter) {
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:9: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterEscapes() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+                            updateFilter(filter);
+                            context.registerReceiver(receiver, filter);
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.java:10: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter);
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testInlineFilter() {
+        lint().files(
+                java(
+                        """
+                    package test.pkg;
+                    import android.content.BroadcastReceiver;
+                    import android.content.Context;
+                    import android.content.Intent;
+                    import android.content.IntentFilter;
+                    public class TestClass1 {
+                        public void testMethod(Context context, BroadcastReceiver receiver) {
+                            context.registerReceiver(receiver,
+                                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expectClean()
+    }
+
+    fun testInlineFilterApply() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            context.registerReceiver(receiver,
+                                    IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                        addAction("qwerty")
+                                    })
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:8: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver,
+                        ^
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterVariableApply() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                addAction("qwerty")
+                            }
+                            context.registerReceiver(receiver, filter)
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:11: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter)
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterVariableApply2() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                addAction(Intent.ACTION_BATTERY_OKAY)
+                            }
+                            context.registerReceiver(receiver, filter.apply {
+                                addAction("qwerty")
+                            })
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:11: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter.apply {
+                        ^
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    fun testFilterComplexChain() {
+        lint().files(
+                kotlin(
+                        """
+                    package test.pkg
+                    import android.content.BroadcastReceiver
+                    import android.content.Context
+                    import android.content.Intent
+                    import android.content.IntentFilter
+                    class TestClass1 {
+                        fun test(context: Context, receiver: BroadcastReceiver) {
+                            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED).apply {
+                                addAction(Intent.ACTION_BATTERY_OKAY)
+                            }
+                            val filter2 = filter
+                            val filter3 = filter2.apply {
+                                addAction(Intent.ACTION_BATTERY_LOW)
+                            }
+                            context.registerReceiver(receiver, filter3)
+                            val filter4 = filter3.apply {
+                                addAction("qwerty")
+                            }
+                            context.registerReceiver(receiver, filter4)
+                        }
+                    }
+                   """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect("""
+                src/test/pkg/TestClass1.kt:19: Warning: Missing RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flag [UnspecifiedRegisterReceiverFlag]
+                        context.registerReceiver(receiver, filter4)
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                0 errors, 1 warnings
+            """.trimIndent())
+    }
+
+    private val broadcastReceiverStub: TestFile = java(
+            """
+            package android.content;
+            public class BroadcastReceiver {
+                // Stub
+            }
+            """
+    ).indented()
+
+    private val contextStub: TestFile = java(
+            """
+            package android.content;
+            public class Context {
+                public static final int RECEIVER_EXPORTED = 0x2;
+                public static final int RECEIVER_NOT_EXPORTED = 0x4;
+                @Nullable
+                public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
+                                                        IntentFilter filter,
+                                                        @RegisterReceiverFlags int flags);
+            }
+            """
+    ).indented()
+
+    private val intentStub: TestFile = java(
+            """
+            package android.content;
+            public class Intent {
+                public static final String ACTION_BATTERY_CHANGED =
+                        "android.intent.action.BATTERY_CHANGED";
+                public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
+                public static final String ACTION_BATTERY_OKAY =
+                        "android.intent.action.BATTERY_OKAY";
+            }
+            """
+    ).indented()
+
+    private val intentFilterStub: TestFile = java(
+            """
+            package android.content;
+            public class IntentFilter {
+                public IntentFilter() {
+                    // Stub
+                }
+                public IntentFilter(String action) {
+                    // Stub
+                }
+                public IntentFilter(String action, String dataType) {
+                    // Stub
+                }
+                public static IntentFilter create(String action, String dataType) {
+                    return null;
+                }
+                public final void addAction(String action) {
+                    // Stub
+                }
+            }
+            """
+    ).indented()
+
+    private val stubs = arrayOf(broadcastReceiverStub, contextStub, intentStub, intentFilterStub)
+}